나는 작동 할 수있는 분할 및 정복 접근법을 생각했습니다.
먼저 전처리 과정에서 입력 크기의 절반 ( n / 3) 보다 작은 모든 숫자를 목록에 삽입해야 합니다.
주어진 문자열 : 0000010101000100
(이 특정 예는 유효합니다)
1에서 16/2까지의 모든 소수 (및 1)를 목록에 삽입하십시오 : {1, 2, 3, 4, 5, 6, 7}
그런 다음 반으로 나눕니다.
100000101 01000100
크기가 1 인 문자열에 도달 할 때까지이 작업을 계속 수행하십시오. 1이 포함 된 모든 크기의 1 문자열에 대해 문자열 목록을 가능성 목록에 추가하십시오. 그렇지 않으면 실패에 대해 -1을 리턴하십시오.
또한 각 시작 색인과 관련된 여전히 가능한 간격 거리 목록을 반환해야합니다. (위에서 만든 목록으로 시작하고 갈 때 숫자를 제거하십시오.) 여기서 빈 목록은 하나만 처리하므로이 시점에서 간격이 가능하다는 의미입니다. 그렇지 않으면 목록에 제외해야하는 간격이 목록에 포함됩니다.
위의 예를 계속 진행하십시오.
1000 0101 0100 0100
10 00 01 01 01 00 01 00
1 0 0 0 0 1 0 1 0 1 0 0 0 1 0 0
첫 번째 결합 단계에서 이제 우리는 두 세트의 여덟 세트가 있습니다. 첫 번째로, 우리는 집합의 가능성을 가지고 있지만, 다른 0이 없기 때문에 1의 간격이 불가능하다는 것을 알게됩니다. 따라서 1의 간격이 불가능하다는 사실에 대해 0 (인덱스)과 {2,3,4,5,7}을 반환합니다. 두 번째로, 우리는 아무것도 없으므로 -1을 반환합니다. 세 번째에서는 인덱스 5에서 공백이 없어진 일치 항목이 있으므로 5, {1,2,3,4,5,7}을 반환합니다. 네 번째 쌍에서 우리는 7, {1,2,3,4,5,7}을 반환합니다. 다섯 번째는 9, {1,2,3,4,5,7}을 반환합니다. 여섯째, -1을 반환하십시오. 일곱 번째는 13, {1,2,3,4,5,7}을 반환합니다. 여덟 번째는 -1을 반환합니다.
다시 네 세트의 네 세트로 결합하면 다음과 같습니다.
1000
: 반환 (0, {4,5,6,7})
0101
: 반환 (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6 , 7})
0100
: 반환 (9, {3,4,5,6,7})
0100
: 반환 (13, {3,4,5,6,7})
8 개 세트로 결합 :
10000101
: 반환 (0, {5,7}), (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6,7})
01000100
: 리턴 (9, {4,7}), (13, {3,4,5,6,7})
16 개 세트로 결합 :
10000101 01000100
우리가 발전함에 따라, 우리는 지금까지 모든 가능성을 점검하고 있습니다. 이 단계까지 우리는 문자열의 끝을 넘어서는 물건을 남겼지 만 이제는 모든 가능성을 확인할 수 있습니다.
기본적으로 우리는 간격이 5와 7 인 첫 번째 1을 확인하고 1과 일치하지 않는 것을 발견합니다. (각 수표는 선형 시간이 아니라 일정하다는 점에 유의하십시오.) 그런 다음 간격이 2, 3, 4, 5, 6 및 7 인 두 번째 검사 (색인 5)를 검사합니다. 실제로 일치합니다.
휴! 다소 긴 알고리즘입니다.
마지막 단계로 인해 O (n log n) 이면 100 %를 모르지만 거기까지의 모든 것은 O (n log n)입니다. 입니다. 나중에 다시 돌아가서 마지막 단계를 개선해 보겠습니다.
편집 : Welbog의 의견을 반영하도록 내 대답을 변경했습니다. 오류로 죄송합니다. 나중에 다시 쓴 내용을 해독 할 시간이 조금 더 있으면 의사 코드도 나중에 작성하겠습니다. ;-)