Einführung
Angenommen, Sie und Ihr Freund spielen ein Spiel. Ihr Freund denkt an eine bestimmte Abfolge von n
Bits, und Ihre Aufgabe ist es, die Abfolge abzuleiten, indem Sie ihm Fragen stellen. Die einzige Art von Frage, die Sie stellen dürfen, ist "Wie lang ist die längste gemeinsame Teilfolge Ihrer Sequenz und S
", wobei S
es sich um eine beliebige Folge von Bits handelt. Je weniger Fragen Sie benötigen, desto besser.
Die Aufgabe
Ihre Aufgabe ist es, ein Programm oder eine Funktion zu schreiben, die eine positive ganze Zahl n
und eine binäre Folge R
von Längen als Eingabe verwendet n
. Die Sequenz kann ein Array von Ganzzahlen, eine Zeichenfolge oder ein anderer sinnvoller Typ Ihrer Wahl sein. Ihr Programm soll die Sequenz ausgeben R
.
Ihr Programm darf nichtR
direkt auf die Sequenz zugreifen . Das einzige, was es tun darf, R
ist, es als Eingabe für die Funktion len_lcs
zusammen mit einer anderen Binärsequenz zu geben S
. Die Funktion len_lcs(R, S)
gibt die Länge der längsten gemeinsamen Teilsequenz von R
und zurück S
. Dies bedeutet die längste Folge von Bits, die als (nicht notwendigerweise zusammenhängende) Folge in beiden R
und auftritt S
. Die Eingänge len_lcs
können unterschiedlich lang sein. Das Programm sollte diese Funktion R
und andere Sequenzen einige Male aufrufen und dann die Sequenz R
basierend auf diesen Informationen rekonstruieren .
Beispiel
Betrachten Sie die Eingänge n = 4
und R = "1010"
. Erstens könnten wir beurteilen len_lcs(R, "110")
, was gibt 3
, da "110"
ist die längste gemeinsame Teilfolge von "1010"
und "110"
. Dann wissen wir , dass R
aus erhalten wird "110"
durch Einfügen eines Bits an einer bestimmten Position. Als nächstes könnten wir versuchen len_lcs(R, "0110")
, was zurückgibt, 3
da die längsten gemeinsamen Teilfolgen sind "110"
und "010"
somit "0110"
nicht korrekt ist. Dann versuchen wir len_lcs(R, "1010")
, was zurückkehrt 4
. Jetzt wissen wir das R == "1010"
, sodass wir diese Sequenz als die richtige Ausgabe zurückgeben können. Dies erforderte 3 Anrufe zu len_lcs
.
Regeln und Wertung
In diesem Repository finden Sie eine Datei mit dem Namen " subsequence_data.txt
100 zufällige binäre Sequenzen mit Längen zwischen 75 und 124". Sie wurden generiert, indem drei zufällige Gleitkommazahlen zwischen 0 und 1 verwendet wurden, der Durchschnitt als angegeben a
wurde und anschließend eine a
Münze mit Voreinstellung geworfen n
wurde. Ihre Punktzahl ist die durchschnittliche Anzahl der Anrufe inlen_lcs
diesen Sequenzen, wobei eine niedrigere Punktzahl besser ist. Ihr Beitrag sollte die Anzahl der Anrufe aufzeichnen. Es gibt keine zeitlichen Beschränkungen, außer dass Sie Ihr Programm für die Datei ausführen sollten, bevor Sie sie senden.
Ihre Vorlage soll deterministisch sein. PRNGs sind zulässig, aber sie müssen das heutige Datum 200116
(oder das nächstgelegene Äquivalent) als zufälligen Startwert verwenden. Es ist Ihnen nicht gestattet, Ihre Einreichung für diese speziellen Testfälle zu optimieren. Wenn ich vermute, dass dies geschieht, werde ich einen neuen Stapel generieren.
Dies ist kein Codegolf, daher wird empfohlen, lesbaren Code zu schreiben. Rosetta Code hat eine Seite mit der längsten gemeinsamen Untersequenz . Sie können das verwenden, um es len_lcs
in der Sprache Ihrer Wahl zu implementieren .
lcs
stattdessen zugreifen könnenlen_lcs
.lcs(R, "01"*2*n)
kehrtR
. ;) Aber das könnte funktionieren, wenn der Anruflcs(R, S)
die Punktzahl umlen(S)
1 erhöhen würde , oder so ähnlich ...Antworten:
Java,
99.0498.4697.66 LCS () AnrufeWie es funktioniert
Beispiel: Unsere zu rekonstruierende Linie ist
00101
. Zuerst ermitteln wir, wie viele Nullen es gibt, indem wir (hier compare = computing lcs with the original string) mit einer Zeichenfolge vergleichen, die nur Nullen enthält00000
. Dann gehen wir jede Position durch, drehen die Taste0
auf a1
und prüfen, ob wir jetzt eine längere gemeinsame Teilzeichenfolge haben. Wenn ja, akzeptiere und gehe zur nächsten Position, wenn nein, drehe die aktuelle1
zurück zu a0
und gehe zur nächsten Position:Optimierungen
Dies ist nur eine "naive" Implementierung. Vielleicht könnte man einen ausgefeilteren Alogrithmus finden, der mehrere Positionen gleichzeitig überprüft. Aber ich bin nicht sicher , ob es wirklich ist ein besseres (zB auf der Grundlage der Berechnung der Parity - Bits ähnlich den Hamming - Code), wie Sie immer nur die beurteilen Länge der gemeinsamen Teilkette .
Für eine bestimmte Ziffernreihe muss dieser Algorithmus genau
#ofDigitsUntilTheLastOccurenceOf1 + 1
überprüft werden. (Subtrahieren Sie eine, wenn die letzte Ziffer eine ist1
.)BEARBEITEN: Eine kleine Optimierung: Wenn wir gerade die zweitletzte Ziffer überprüft haben und wir noch eine einfügen müssen
1
, wissen wir sicher, dass sie sich an der allerletzten Position befinden muss, und können die entsprechende Prüfung auslassen.EDIT2: Mir ist gerade aufgefallen, dass Sie die obigen Gedanken auf die letzten anwenden
k
können.Es könnte natürlich möglich sein, mit dieser Optimierung eine etwas niedrigere Punktzahl zu erzielen, indem Sie zuerst alle Zeilen neu anordnen, da es sein könnte, dass Sie am Ende mehr Zeilen mit Einsen erhalten, aber das wäre natürlich eine Optimierung für den aktuellen Wert Testfälle, die nicht mehr lustig sind.
Laufzeit
Die Obergrenze liegt bei
O(#NumberOfBits)
.Vollständiger Code
Hier der vollständige Code:
quelle
1
, was bedeutet, dass nur noch Nullen übrig sind.