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 iund nicht negativ geschrieben werden kann j(da wir keine Eingabe verarbeiten müssen 0), und das n*nist nur die Summe der ersten nungeraden 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 nungeraden Ganzzahlen sind, können wir beispielsweise eine Quadrateingabe wie die folgende zuordnen:
(^.|..\1)+$
..\1Kann bei der ersten Iteration nicht funktionieren, da \1noch 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 ..\1gü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*imü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*inimmt iIterationen, so dass wir aufgenommen haben iDinge 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 iungerade 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 1verschoben (Initialisierung iauf 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)). \1Entspricht der vorherigen iund (?<1>.\1)aktualisiert die Gruppe 1mit i+1. In Bezug auf das Neue i haben wir nur 2i-1Charaktere gefunden. Genau das, was wir brauchen.
Wenn wir fertig sind, haben wir ein Quadrat gefunden i*iund die Gruppe enthält 1noch iZeichen.
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 .\1nur 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*iBegriff. Wir kombinieren dies mit der j*jTatsache, dass für die j*jBerechnung noch jIterationen erforderlich sind. Bei jeder Iteration rücken wir den Cursor also um imit 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)))*