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