Retina , 66 63 45 43 36 Bytes
^()(\1(?<1>.\1))+(\1(.(?(4).\4)))*$
Trotz des Titels "Retina" ist dies nur eine einfache .NET-Regex, die unäre Darstellungen von Loeschschen Zahlen akzeptiert .
Die Eingaben 999 und 1000 dauern weniger als eine Sekunde.
Probieren Sie es online! (Die erste Zeile aktiviert eine durch Zeilenvorschub getrennte Testsuite, und die nächsten beiden Zeilen kümmern sich der Einfachheit halber um die Konvertierung in Unary.)
Erläuterung
Die Lösung basiert auf der Klassifizierung, dass die Eingabe als i*i + j*(i + j)
positiv i
und nicht negativ geschrieben werden kann j
(da wir keine Eingabe verarbeiten müssen 0
), und das n*n
ist nur die Summe der ersten n
ungeraden ganzen Zahlen. Golfen war eine interessante Übung in Vorwärtsreferenzen.
Eine "Vorwärtsreferenz" ist, wenn Sie eine Rückwärtsreferenz in die Gruppe einfügen, auf die sie verweist. Dies funktioniert natürlich nicht, wenn die Gruppe zum ersten Mal verwendet wird, da noch keine Rückverweise vorhanden sind. Wenn Sie dies jedoch in eine Schleife einfügen, erhält die Rückverweisung jedes Mal die Erfassung der vorherigen Iteration. Auf diese Weise können Sie mit jeder Iteration ein größeres Capture erstellen. Dies kann verwendet werden, um sehr kompakte Muster für Dinge wie Dreieckszahlen, Quadrate und Fibonacci-Zahlen herzustellen.
Anhand der Tatsache, dass Quadrate nur Summen der ersten n
ungeraden Ganzzahlen sind, können wir beispielsweise eine Quadrateingabe wie die folgende zuordnen:
(^.|..\1)+$
..\1
Kann bei der ersten Iteration nicht funktionieren, da \1
noch kein Wert vorhanden ist. Also fangen wir damit an ^.
, ein einzelnes Zeichen in einer Gruppe festzuhalten 1
. Bei nachfolgenden Iterationen werden ^.
aufgrund des Ankers keine Übereinstimmungen mehr gefunden, sondern sind jetzt ..\1
gültig. Es entspricht zwei Zeichen mehr als die vorherige Iteration und aktualisiert die Erfassung. Auf diese Weise passen wir steigende ungerade Zahlen an und erhalten nach jeder Iteration ein Quadrat.
Leider können wir diese Technik nicht so verwenden, wie sie ist. Nach dem Matching i*i
müssen wir auch bekommen i
, damit wir es multiplizieren können j
. Ein einfache (aber lange) Weg , dies zu tun , ist die Tatsache zunutze zu machen , dass Anpassung i*i
nimmt i
Iterationen, so dass wir aufgenommen haben i
Dinge in der Gruppe 1
. Wir könnten jetzt Bilanzkreise verwenden , um dies zu extrahieren i
, aber wie gesagt, das ist teuer.
Stattdessen habe ich mir eine andere Methode ausgedacht, um diese "Summe aufeinanderfolgender ungerader Ganzzahlen" zu schreiben i
, die sich am Ende auch in einer Erfassungsgruppe ergibt . Natürlich ist die i
ungerade Zahl gerade 2i-1
. Dies gibt uns die Möglichkeit, die Vorwärtsreferenz bei jeder Iteration nur um 1 zu erhöhen. Das ist dieser Teil:
^()(\1(?<1>.\1))+
Dadurch wird ()
nur ein leeres Capture auf die Gruppe 1
verschoben (Initialisierung i
auf 0
). Dies entspricht ^.|
in etwa der oben beschriebenen einfachen Lösung, ist jedoch |
in diesem Fall etwas schwieriger.
Dann haben wir die Hauptschleife (\1(?<1>.\1))
. \1
Entspricht der vorherigen i
und (?<1>.\1)
aktualisiert die Gruppe 1
mit i+1
. In Bezug auf das Neue i
haben wir nur 2i-1
Charaktere gefunden. Genau das, was wir brauchen.
Wenn wir fertig sind, haben wir ein Quadrat gefunden i*i
und die Gruppe enthält 1
noch i
Zeichen.
Der zweite Teil ist näher an der einfachen quadratischen Übereinstimmung, die ich oben gezeigt habe. Ignorieren wir zunächst den Rückverweis auf 1
:
(.(?(4).\1))*
Dies ist im Grunde dasselbe wie (^.|..\4)*
, außer dass wir es nicht nutzen können, ^
weil wir nicht am Anfang der Zeichenkette stehen. Stattdessen verwenden wir eine Bedingung, die .\1
nur dann mit der zusätzlichen übereinstimmt, wenn wir bereits group verwendet haben 4
. Tatsächlich ist dies jedoch genau das gleiche. Das gibt uns j*j
.
Das einzige, was fehlt, ist der j*i
Begriff. Wir kombinieren dies mit der j*j
Tatsache, dass für die j*j
Berechnung noch j
Iterationen erforderlich sind. Bei jeder Iteration rücken wir den Cursor also um i
mit vor \1
. Wir müssen nur sicherstellen, dass das nicht in Gruppen geschrieben wird 4
, da dies mit übereinstimmenden ungeraden Zahlen in Konflikt geraten würde. So kommen wir zum:
(\1(.(?(4).\1)))*