Un'altra soluzione
Questo è, a mio avviso, uno dei problemi più interessanti sul sito. Devo ringraziare deadcode per averlo riportato in cima.
^((^|xx)(^|\3\4\4)(^|\4x{12})(^x|\1))*$
39 byte , senza condizionali o asserzioni ... sorta di. Le alternanze, mentre vengono utilizzate ( ^|
), sono un tipo di condizionale in un certo senso, per selezionare tra "prima iterazione" e "non prima iterazione".
Questo regex può essere visto funzionare qui: http://regex101.com/r/qA5pK3/1
Sia PCRE che Python interpretano correttamente il regex, ed è stato anche testato in Perl fino a n = 128 , inclusi n 4 -1 e n 4 +1 .
definizioni
La tecnica generale è la stessa delle altre soluzioni già pubblicate: definire un'espressione autoreferenziale che su ciascuna iterazione successiva corrisponde a una lunghezza pari al termine successivo della funzione di differenza diretta, D f , con un quantificatore illimitato ( *
). Una definizione formale della funzione di differenza in avanti:
Inoltre, è possibile definire anche funzioni di differenza ordine superiore:
O, più in generale:
La funzione di differenza in avanti ha molte proprietà interessanti; è alle sequenze ciò che la derivata è alle funzioni continue. Ad esempio, D f di un polinomio di n ° ordine sarà sempre un polinomio di n-1 ° ordine, e per qualsiasi i , se D f i = D f i + 1 , allora la funzione f è esponenziale, più o meno allo stesso modo che la derivata di e x è uguale a se stessa. La funzione discreta più semplice per cui f = D f è 2 n .
f (n) = n 2
Prima di esaminare la soluzione di cui sopra, iniziamo con qualcosa di un po 'più semplice: una regex che corrisponde a stringhe le cui lunghezze sono un quadrato perfetto. Esame della funzione di differenza in avanti:
Significato, la prima iterazione dovrebbe corrispondere a una stringa di lunghezza 1 , la seconda a una stringa di lunghezza 3 , la terza a una stringa di lunghezza 5 , ecc. E, in generale, ogni iterazione dovrebbe corrispondere a una stringa due più lunga della precedente. Il regex corrispondente segue quasi direttamente da questa affermazione:
^(^x|\1xx)*$
Si può vedere che la prima iterazione corrisponderà a una sola x
e ogni successiva iterazione corrisponderà a una stringa due più lunga della precedente, esattamente come specificato. Ciò implica anche un test quadrato perfetto sorprendentemente breve in perl:
(1x$_)=~/^(^1|11\1)*$/
Questo regex può essere ulteriormente generalizzato per adattarsi a qualsiasi lunghezza n -gonale:
Numeri triangolari:
^(^x|\1x{1})*$
Numeri quadrati:
^(^x|\1x{2})*$
Numeri pentagonali:
^(^x|\1x{3})*$
Numeri esagonali:
^(^x|\1x{4})*$
eccetera.
f (n) = n 3
Passando a n 3 , esaminando ancora una volta la funzione di differenza in avanti:
Potrebbe non essere immediatamente chiaro come implementarlo, quindi esaminiamo anche la seconda funzione di differenza:
Pertanto, la funzione di differenza in avanti non aumenta di un valore costante, ma piuttosto di un valore lineare. È bello che il valore iniziale (' -1 °') di D f 2 sia zero, il che salva un'inizializzazione sulla seconda iterazione. La regex risultante è la seguente:
^((^|\2x{6})(^x|\1))*$
La prima iterazione corrisponderà a 1 , come prima, la seconda corrisponderà a una stringa 6 più lunga ( 7 ), la terza corrisponderà a una stringa 12 più lunga ( 19 ), ecc.
f (n) = n 4
La funzione di differenza in avanti per n 4 :
La seconda funzione di differenza diretta:
La terza funzione di differenza in avanti:
Ora è brutto. I valori iniziali per D f 2 e D f 3 sono entrambi diversi da zero, 2 e 12 rispettivamente, che dovranno essere presi in considerazione. Probabilmente hai già capito che il regex seguirà questo schema:
^((^|\2\3{b})(^|\3x{a})(^x|\1))*$
Poiché D f 3 deve corrispondere a una lunghezza di 12 nella seconda iterazione, a è necessariamente 12 . Ma poiché aumenta di 24 ogni termine, il successivo annidamento più profondo deve utilizzare due volte il valore precedente, implicando b = 2 . L'ultima cosa da fare è inizializzare D f 2 . Poiché D f 2 influenza direttamente D f , che è in definitiva ciò che vogliamo abbinare, il suo valore può essere inizializzato inserendo l'atomo appropriato direttamente nella regex, in questo caso (^|xx)
. La regex finale diventa quindi:
^((^|xx)(^|\3\4{2})(^|\4x{12})(^x|\1))*$
Ordini superiori
Un polinomio di quinto ordine può essere abbinato alla seguente regex:
^((^|\2\3{c})(^|\3\4{b})(^|\4x{a})(^x|\1))*$
f (n) = n 5 è un esercizio abbastanza semplice, poiché i valori iniziali per la seconda e la quarta funzione di differenza in avanti sono zero:
^((^|\2\3)(^|\3\4{4})(^|\4x{30})(^x|\1))*$
Per polinomi a sei ordini:
^((^|\2\3{d})(^|\3\4{c})(^|\4\5{b})(^|\5x{a})(^x|\1))*$
Per i polinomi del settimo ordine:
^((^|\2\3{e})(^|\3\4{d})(^|\4\5{c})(^|\5\6{b})(^|\6x{a})(^x|\1))*$
eccetera.
Si noti che non tutti i polinomi possono essere abbinati esattamente in questo modo, se uno qualsiasi dei coefficienti necessari è non intero. Ad esempio, n 6 richiede che a = 60 , b = 8 e c = 3/2 . Questo può essere risolto, in questo caso:
^((^|xx)(^|\3\6\7{2})(^|\4\5)(^|\5\6{2})(^|\6\7{6})(^|\7x{60})(^x|\1))*$
Qui ho cambiato b in 6 e c in 2 , che hanno lo stesso prodotto dei valori sopra indicati. È importante che il prodotto non cambi, poiché a · b · c ·… controlla la funzione di differenza costante, che per un polinomio del sesto ordine è D f 6 . Sono presenti due atomi di inizializzazione: uno per inizializzare D f a 2 , come con n 4 , e l'altro per inizializzare la quinta funzione di differenza su 360 , aggiungendo contemporaneamente i due mancanti da b .