Ich dachte an einen Divide-and-Conquer-Ansatz, der funktionieren könnte.
Zunächst müssen Sie bei der Vorverarbeitung alle Zahlen, die kleiner als die Hälfte Ihrer Eingabegröße ( n / 3) sind, in eine Liste einfügen .
Gegeben eine Zeichenfolge: 0000010101000100
(Beachten Sie, dass dieses spezielle Beispiel gültig ist)
Fügen Sie alle Primzahlen (und 1) von 1 bis (16/2) in eine Liste ein: {1, 2, 3, 4, 5, 6, 7}
Dann teilen Sie es in zwei Hälften:
100000101 01000100
Machen Sie so weiter, bis Sie zu Zeichenfolgen der Größe 1 gelangen. Fügen Sie für alle Zeichenfolgen der Größe 1 mit einer 1 den Index der Zeichenfolge zur Liste der Möglichkeiten hinzu. Andernfalls geben Sie -1 für einen Fehler zurück.
Sie müssen auch eine Liste der noch möglichen Abstandsabstände zurückgeben, die jedem Startindex zugeordnet sind. (Beginnen Sie mit der Liste, die Sie oben erstellt haben, und entfernen Sie die Zahlen, während Sie fortfahren.) Hier bedeutet eine leere Liste, dass Sie nur mit einer 1 arbeiten und daher an dieser Stelle ein beliebiger Abstand möglich ist. Andernfalls enthält die Liste Abstände, die ausgeschlossen werden müssen.
Fahren Sie also mit dem obigen Beispiel fort:
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
Im ersten Kombinationsschritt haben wir jetzt acht Zweiergruppen. Im ersten Fall haben wir die Möglichkeit einer Menge, aber wir lernen, dass ein Abstand von 1 unmöglich ist, weil die andere Null da ist. Wir geben also 0 (für den Index) und {2,3,4,5,7} zurück, da ein Abstand von 1 unmöglich ist. Im zweiten haben wir nichts und geben so -1 zurück. Im dritten haben wir eine Übereinstimmung ohne Abstände in Index 5, also geben Sie 5, {1,2,3,4,5,7} zurück. Im vierten Paar geben wir 7 zurück, {1,2,3,4,5,7}. Im fünften geben Sie 9, {1,2,3,4,5,7} zurück. Im sechsten Fall geben Sie -1 zurück. Im siebten geben Sie 13 zurück, {1,2,3,4,5,7}. Im achten geben Sie -1 zurück.
Wenn wir noch einmal vier Vierergruppen kombinieren, haben wir:
1000
: Return (0, {4,5,6,7})
0101
: Return (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6 , 7})
0100
: Return (9, {3,4,5,6,7})
0100
: Return (13, {3,4,5,6,7})
Kombinieren zu Achtergruppen:
10000101
: Rückgabe (0, {5,7}), (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6,7})
01000100
: Rückgabe (9, {4,7}), (13, {3,4,5,6,7})
Kombinieren zu einem Satz von 16:
10000101 01000100
Im weiteren Verlauf prüfen wir alle Möglichkeiten. Bis zu diesem Schritt haben wir Dinge hinterlassen, die über das Ende der Zeichenfolge hinausgingen, aber jetzt können wir alle Möglichkeiten prüfen.
Grundsätzlich überprüfen wir die erste 1 mit Abständen von 5 und 7 und stellen fest, dass sie nicht mit 1 übereinstimmen. (Beachten Sie, dass jede Prüfung KONSTANT und nicht linear ist.) Dann prüfen wir die zweite (Index 5) mit Abständen von 2, 3, 4, 5, 6 und 7 - oder wir würden, aber wir können seitdem bei 2 anhalten das passt tatsächlich zusammen.
Puh! Das ist ein ziemlich langer Algorithmus.
Ich weiß nicht 100%, ob es wegen des letzten Schritts O (n log n) ist , aber alles bis dahin ist definitiv O (n log n) , soweit ich das beurteilen kann. Ich werde später darauf zurückkommen und versuchen, den letzten Schritt zu verfeinern.
EDIT: Meine Antwort wurde geändert, um Welbogs Kommentar widerzuspiegeln. Entschuldigung für den Fehler. Ich werde später auch einen Pseudocode schreiben, wenn ich etwas mehr Zeit habe, um zu entziffern, was ich wieder geschrieben habe. ;-);