같은 수의 0과 1을 가진 모든 이진 시퀀스를 어떻게 효율적으로 생성합니까?


10

이진 계열 길이가 단 정렬 순서되고 각각의 것을 하나이고 0 또는 1 . 이러한 모든 이진 시퀀스를 생성하기 위해 다음과 같은 방식으로 명백한 이진 트리 구조를 사용할 수 있습니다. 루트는 "빈"이지만 각 왼쪽 자식 은 기존 문자열 에 0 을 추가 하고 오른쪽 자식을 1에 추가합니다 . 이제 각 이진 시퀀스는 단순히 루트에서 시작하여 잎에서 끝나는 길이 n + 1 의 경로입니다 .x 1 , , x n x jnx1,,xnxj0101n+1

내 질문은 다음과 같습니다.

정확히 n 개의 0과 n 개의 1 을 갖는 길이 의 모든 이진 문자열 만 생성하려는 경우 더 잘 수행 할 수 있습니까 ?2nnn

"우리가 더 잘할 수있다"는 것은 먼저 전체 트리를 구축 한 다음 같은 수의 "왼쪽"과 "오른쪽"가장자리를 가진 경로를 찾으려고하는 어리석은 알고리즘보다 복잡성이 낮아야 함을 의미합니다.


1에서 2 n 사이의 범위에서 엄격하게 증가하는 시퀀스를 효율적으로 생성하는 방법을 찾을 수 있습니까 ? n2n
Cornelius Brand

복잡성에 대해서는 언급 할 수 없지만 순진한 알고리즘은 일종의 역 추적 방식을 사용하여 한 모퉁이에서 대각선으로 사각형 격자의 가장자리를 따라 보행을 생성합니다. 이것은 01과 10이 (나무와는 달리) 같은 위치에 있지만 역 추적을 통해 우리는이 역사를 알고 있음을 의미합니다.
Hendrik Jan

다른 메모로는 -iterator 의 Java 구현이 . (nk)
Pål GD

답변:


6

분명히 길이가 이진 문자열이 있습니다. 이진을 탐색하려면 알고리즘이 각 노드를 한 번 방문해야합니다. 즉 단계. 2 n 2 n i = 0 2 i = 2 2 n + 11 = O ( 4 n )4n2n

i=02n2i=22n+11=O(4n)

당신이 묘사 한 트리를 가로 지르는 재귀 알고리즘을 고려하지만 그 길에서 1과 0의 수를 세어 봅시다. 즉, 트리의 좋은 부분만을 가로지 릅니다.
그러나 0과 1을 가진 이진 문자열 은 몇 개입니까? 길이 의 문자열에 대해 1을 선택 하고 2 단계에서 스털링 공식을 사용합니다. , N , N (2) , N ( 2 Nnnn2n

(2nn)=(2n)!(n!)2=4nπn(1+O(1/n))

편집
Peter Shor의 의견 덕분에 두 번째 알고리즘에 필요한 단계 수를 분석 할 수 있습니다.이 알고리즘은 1과 0을 계산합니다. 아래에서 그의 의견을 인용하고 있습니다.

정확히 0과 1을 가진 모든 이진 시퀀스를 찾고 싶습니다 . 각 노드가 최대 0과 1의 시퀀스 인 이진 트리를 순회합니다 . 0보다 크거나 1 보다 큰 노드를 방문 할 필요가 없습니다 . 몇 개의 노드를 방문해야합니까? 있다 와 문자열 공의와 1 개의를. 온통이 합산 준다 . 이제 노드 당 일정한 평균 비용으로 이러한 각 노드를 방문해야합니다. 우리는 각각의 왼쪽 자식을 먼저 방문하고 오른쪽 자식을 두 번째 방문하여이를 수행 할 수 있습니다.n 2 n n n ( i + jnn2nnn iji,jn n i = 0 n j = 0 ( i + j(i+ji)iji,jni=0nj=0n(i+ji)=(2n+2n+1)1

스털링 공식을 다시 사용하면 새 알고리즘의 실행 시간으로 .

(2n+2n+1)1=4n+11n+1(1+O(1/n))1=O(4nn)

좀 더 조심해야합니다. 각 문자열을 생성 한 후 시간에 처리합니다. 따라서 모든 균형 잡힌 문자열을 처리하는 데는 시간이 걸립니다 . 최적화 된 "silly"생성 알고리즘이 실제로 이면 버그 기회 이외의 더 똑똑한 알고리즘으로 전환하여 얻을 수있는 것은 없습니다. Ω(n)Ω(4nn)O(4n)
Yuval Filmus 2016 년

@Yuval Filmus : "문자열 처리"란 정확히 무엇을 의미합니까? 출력에 소요 된 시간 확실히 을 의미하는 경우 , "silly"알고리즘의 실행 시간에도 해당 요소를 고려해야합니다.이 때 입니다. Θ(n)O(4nn)
tranisstor 2016 년

2
내 요점은 과 의 차이에 관심이 있다면 최소한 정확한 실행 시간을 명시해야한다는 것입니다. 는 두 알고리즘 사이의 잠재적 인 차이를 나타내기에 충분하지 않습니다. 또한 제안 된 새 알고리즘을 신중하게 분석해야합니다. 이러한 "무시할 수있는"작은 요인으로 인해 사소한 알고리즘보다 느리지 않습니다. 4n~ O (4n)4n/nO~(4n)
Yuval Filmus 2016 년

2
"나쁜 부분"도 포함시키지 않고 어떻게 나무의 "좋은 부분"을 만들 수 있습니까? 루트에서 노드까지의 경로에 왼쪽 자식 또는 오른쪽 자식 이없는 트리의 모든 노드를 포함해야 합니다. 이것은 작동하지만 작동한다는 것을 보여주기 위해 추가 인수가 필요합니다. 특히, 공식을 사용해야합니다 . n n i = 0n j = 0 ( i + jnni=0nj=0n(i+ji)=(2n+2n+1)1
피터 쇼어

2
정확히 0과 1을 가진 모든 이진 시퀀스를 찾고 싶습니다 . 각 노드가 최대 0과 1의 시퀀스 인 이진 트리를 순회합니다 . 0보다 크거나 1 보다 큰 노드를 방문 할 필요가 없습니다 . 몇 개의 노드를 방문해야합니까? 있다 와을 문자열 공의와 1 개의. 온통이 합산 준다 . 이제 노드 당 일정한 평균 비용으로 이러한 각 노드를 방문해야합니다. 우리는 각각의 왼쪽 자식을 먼저 방문하고 오른쪽 자식을 두 번째 방문하여이를 수행 할 수 있습니다.n 2 n n n ( i + jnn2nnn iji,jn n i = 0 n j = 0 ( i + j(i+ji)iji,jni=0nj=0n(i+ji)=(2n+2n+1)1
피터 쇼어

2

어쩌면 나는 두껍지 만 원래의 질문은 길이 2n의 모든 이진 시퀀스의 트리를 통과하고 균형이 맞는 것만 출력하는 것보다 더 효율적인 길이 2n의 모든 "균형"이진 시퀀스를 생성하는 방법을 요구했습니다 . 그렇다면 왜 나무를 사용합니까?

이러한 모든 시퀀스를 생성하는 재귀 알고리즘의 유사 코드는 다음과 같습니다 (키워드 "yield"는 시퀀스를 출력으로 보냅니다).

function all-balanced(n) {
  all-specified( "", n, n );
};

function all-specified( currentString, zeroes, ones ) {

  if (zeroes == 0) {
    for i = 0 to ones {
      currentString += "1";
    };
    yield currentString;
    return;
  };

  if (ones == 0) {
    for i = 0 to zeroes {
      currentString += "0";
    };
    yield currentString;
    return;
  };

  all-specified( currentString+"0", zeroes-1, ones );
  all-specified( currentString+"1", zeroes, ones-1 );
  return;
};

내가 잘못 이해하고 있다면 말해주십시오. 그러나 이것은 실제로 제기 된 문제에 대한 가장 효율적인 대답에 관한 것으로 보입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.