私は分割統治法がうまくいくかもしれないと考えました。
まず、前処理では、入力サイズの半分( n / 3)未満のすべての数値をリストに挿入する必要があります。
与えられた文字列:(0000010101000100
この特定の例は有効であることに注意してください)
1から(16/2)までのすべての素数(および1)をリストに挿入します:{1、2、3、4、5、6、7}
次に、それを半分に分割します。
100000101 01000100
サイズ1の文字列に到達するまで、これを続けます。すべてのサイズ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
最初の結合ステップでは、2つのセットが8つあります。最初に、セットの可能性がありますが、他のゼロが存在するため、1による間隔は不可能であることがわかります。したがって、1による間隔が不可能であるという事実のために、0(インデックスの場合)と{2,3,4,5,7}を返します。2番目の例では、何もないため、-1を返します。3番目では、インデックス5でスペースが削除されていない一致があるため、5、{1,2,3,4,5,7}を返します。4番目のペアでは、7、{1,2,3,4,5,7}を返します。5番目に、9、{1,2,3,4,5,7}を返します。6番目に、-1を返します。7番目に、13、{1,2,3,4,5,7}を返します。8番目に、-1を返します。
再び4つの4つのセットに組み合わせると、次のようになります。
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
:Return(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
私たちが進歩するにつれて、私たちはこれまでのところすべての可能性をチェックし続けています。このステップまで、文字列の終わりを超えたものを残しましたが、これですべての可能性を確認できます。
基本的に、最初の1を5と7の間隔でチェックし、それらが1と並んでいないことを確認します。(各チェックは線形時間ではなく一定であることに注意してください)次に、2、3、4、5、6、および7の間隔で2番目のチェック(インデックス5)をチェックします。それは実際に一致します。
ふぅ!これはかなり長いアルゴリズムです。
最後のステップでO(n log n)かどうかは100%わかりませんが、私が知る限り、そこまでのすべては間違いなくO(n log n)です。後でこれに戻り、最後のステップを改善してみます。
編集:ウェルボグのコメントを反映するように私の答えを変更しました。エラーでごめんなさい。後で、もう一度書いたものを解読する時間が少しできたら、擬似コードも書きます。;-)