Eine andere Lösung
Dies ist meiner Meinung nach eines der interessantesten Probleme auf der Website. Ich muss Deadcode dafür danken, dass er wieder nach oben geschoben wurde .
^((^|xx)(^|\3\4\4)(^|\4x{12})(^x|\1))*$
39 Bytes , ohne Bedingungen oder Zusicherungen ... irgendwie. Die Alternationen, wie sie verwendet werden ( ^|
), sind in gewisser Weise eine Art Bedingung, um zwischen "erster Iteration" und "nicht erster Iteration" zu wählen.
Dieser reguläre Ausdruck funktioniert hier: http://regex101.com/r/qA5pK3/1
Sowohl PCRE als auch Python interpretieren den regulären Ausdruck korrekt und er wurde auch in Perl bis zu n = 128 getestet , einschließlich n 4 -1 und n 4 +1 .
Definitionen
Die allgemeine Technik ist dieselbe wie bei den anderen bereits veröffentlichten Lösungen: Definieren Sie einen selbstreferenzierenden Ausdruck, der bei jeder nachfolgenden Iteration einer Länge entspricht, die dem nächsten Term der Vorwärtsdifferenzfunktion D f mit einem unbegrenzten Quantifizierer ( *
) entspricht. Eine formale Definition der Vorwärtsdifferenzfunktion:
Zusätzlich können auch Differenzfunktionen höherer Ordnung definiert werden:
Oder allgemeiner:
Die Vorwärtsdifferenzfunktion hat viele interessante Eigenschaften; es ist zu Sequenzen, was die Ableitung zu stetigen Funktionen ist. Zum Beispiel wird D f eines Polynoms n- ter Ordnung immer ein Polynom n-1- ter Ordnung sein, und für jedes i ist , wenn D f i = D f i + 1 , die Funktion f auf ähnliche Weise exponentiell dass die Ableitung von e x gleich sich selbst ist. Die einfachste diskrete Funktion, für die f = D f ist, ist 2 n .
f (n) = n 2
Bevor wir die obige Lösung untersuchen, wollen wir mit etwas Einfacherem beginnen: einem regulären Ausdruck, der Zeichenfolgen entspricht, deren Länge ein perfektes Quadrat ist. Untersuchen der Vorwärtsdifferenzfunktion:
Das heißt, die erste Iteration sollte mit einer Zeichenfolge der Länge 1 , die zweite mit einer Zeichenfolge der Länge 3 , die dritte mit einer Zeichenfolge der Länge 5 usw. übereinstimmen, und im Allgemeinen sollte jede Iteration mit einer Zeichenfolge übereinstimmen, die zwei länger als die vorherige ist. Der entsprechende reguläre Ausdruck folgt fast direkt aus dieser Aussage:
^(^x|\1xx)*$
Es ist ersichtlich, dass die erste Iteration nur mit einer übereinstimmt x
und jede nachfolgende Iteration genau wie angegeben mit einer Zeichenfolge, die zwei länger als die vorherige ist. Dies impliziert auch einen erstaunlich kurzen perfekten Quadrattest in Perl:
(1x$_)=~/^(^1|11\1)*$/
Dieser reguläre Ausdruck kann weiter verallgemeinert werden, um mit jeder n- eckigen Länge übereinzustimmen:
Dreieckszahlen:
^(^x|\1x{1})*$
Quadratzahl:
^(^x|\1x{2})*$
Fünfeckige Zahlen:
^(^x|\1x{3})*$
Sechseckige Zahlen:
^(^x|\1x{4})*$
etc.
f (n) = n 3
Gehen Sie weiter zu n 3 und untersuchen Sie noch einmal die Vorwärtsdifferenzfunktion:
Es ist möglicherweise nicht sofort ersichtlich, wie dies implementiert werden kann. Daher untersuchen wir auch die zweite Differenzfunktion:
Die Vorwärtsdifferenzfunktion steigt also nicht um eine Konstante, sondern um einen linearen Wert. Es ist schön, dass der Anfangswert (' -1 th') von D f 2 Null ist, was eine Initialisierung bei der zweiten Iteration sichert. Der resultierende reguläre Ausdruck ist der folgende:
^((^|\2x{6})(^x|\1))*$
Die erste Iteration stimmt mit 1 überein , wie zuvor, die zweite mit einer längeren Zeichenfolge 6 ( 7 ), die dritte mit einer längeren Zeichenfolge 12 ( 19 ) usw.
f (n) = n 4
Die Vorwärtsdifferenzfunktion für n 4 :
Die zweite Vorwärtsdifferenzfunktion:
Die dritte Vorwärtsdifferenzfunktion:
Das ist hässlich. Die Anfangswerte für D f 2 und D f 3 sind beide ungleich Null, 2 bzw. 12 , was berücksichtigt werden muss. Sie haben wahrscheinlich schon herausgefunden, dass der reguläre Ausdruck diesem Muster folgt:
^((^|\2\3{b})(^|\3x{a})(^x|\1))*$
Weil der D f 3 muss eine Länge von Match 12 auf der zweiten Iteration, a ist notwendigerweise 12 . Da es sich jedoch mit jedem Term um 24 erhöht , muss die nächste tiefere Verschachtelung ihren vorherigen Wert zweimal verwenden, was bedeutet, dass b = 2 ist . Als letztes müssen Sie D f 2 initialisieren . Da D f 2 Einflüsse D f direkt, was letztlich ist das, was wir passen wollen, kann ihr Wert durch Einsetzen des entsprechende Atom initialisiert wird direkt in den regulären Ausdruck, in diesem Fall (^|xx)
. Der endgültige reguläre Ausdruck wird dann:
^((^|xx)(^|\3\4{2})(^|\4x{12})(^x|\1))*$
Höhere Aufträge
Ein Polynom fünfter Ordnung kann mit dem folgenden regulären Ausdruck verglichen werden:
^((^|\2\3{c})(^|\3\4{b})(^|\4x{a})(^x|\1))*$
f (n) = n 5 ist eine ziemlich einfache Übung, da die Anfangswerte sowohl für die zweite als auch für die vierte Vorwärtsdifferenzfunktion Null sind:
^((^|\2\3)(^|\3\4{4})(^|\4x{30})(^x|\1))*$
Für sechs Ordnungspolynome:
^((^|\2\3{d})(^|\3\4{c})(^|\4\5{b})(^|\5x{a})(^x|\1))*$
Für Polynome siebter Ordnung:
^((^|\2\3{e})(^|\3\4{d})(^|\4\5{c})(^|\5\6{b})(^|\6x{a})(^x|\1))*$
etc.
Beachten Sie, dass nicht alle Polynome auf genau diese Weise abgeglichen werden können, wenn einer der erforderlichen Koeffizienten nicht ganzzahlig ist. Zum Beispiel erfordert n 6 , dass a = 60 , b = 8 und c = 3/2 ist . Dies kann in diesem Fall umgangen werden:
^((^|xx)(^|\3\6\7{2})(^|\4\5)(^|\5\6{2})(^|\6\7{6})(^|\7x{60})(^x|\1))*$
Hier habe ich b auf 6 und c auf 2 geändert , die das gleiche Produkt wie die oben angegebenen Werte haben. Es ist wichtig, dass sich das Produkt nicht ändert, da a · b · c ·… die konstante Differenzfunktion steuert, die für ein Polynom sechster Ordnung D f 6 ist . Es sind zwei Initialisierungsatome vorhanden: eines zum Initialisieren von D f auf 2 , wie bei n 4 , und das andere zum Initialisieren der fünften Differenzfunktion auf 360 , während gleichzeitig die fehlenden zwei von b hinzugefügt werden .