Inne rozwiązanie
To, moim zdaniem, jeden z najciekawszych problemów na stronie. Muszę podziękować deadcode za podbicie go z powrotem na samą górę.
^((^|xx)(^|\3\4\4)(^|\4x{12})(^x|\1))*$
39 bajtów , bez żadnych warunków i zapewnień ... w pewnym sensie. Alternacje, w miarę ich wykorzystywania ( ^|
), są rodzajem warunkowego sposobu wyboru między „pierwszą iteracją” a „nie pierwszą iteracją”.
Ten regex można zobaczyć tutaj: http://regex101.com/r/qA5pK3/1
Zarówno PCRE, jak i Python poprawnie interpretują wyrażenie regularne, a także zostało przetestowane w Perlu do n = 128 , w tym n 4 -1 i n 4 +1 .
Definicje
Ogólna technika jest taka sama jak w przypadku innych rozwiązań już umieszczone: określenia ekspresji odniesienie lokalne, które przy każdej kolejnej iteracji odpowiada długości równej następnego okresu przedniej funkcji różnicy D f , z nieograniczonym kwantyfikator ( *
). Formalna definicja funkcji różnicy w przód:
Dodatkowo można również zdefiniować funkcje różnic wyższych rzędów:
Lub bardziej ogólnie:
Funkcja różnicy w przód ma wiele interesujących właściwości; chodzi o sekwencjonowanie pochodnej funkcji ciągłych. Na przykład, D C O mocy n p Wielomian stopnia zawsze będzie N-1 p Wielomian stopnia, a dla każdej I , jeśli D f I = D, F i + 1 , wtedy funkcja f jest wykładniczy, w taki sam sposób, że pochodna e x jest sobie równa. Najprostsza funkcja dyskretna, dla której f = D f wynosi 2 n .
f (n) = n 2
Zanim przeanalizujemy powyższe rozwiązanie, zacznijmy od czegoś nieco łatwiejszego: wyrażenia regularnego, które pasuje do ciągów, których długości są idealnym kwadratem. Analiza funkcji różnicy naprzód:
Oznacza to, że pierwsza iteracja powinna pasować do ciągu o długości 1 , drugi ciąg o długości 3 , trzeci ciąg o długości 5 itd. I ogólnie każda iteracja powinna pasować do ciągu o dwa dłuższe niż poprzednie. Odpowiednie wyrażenie regularne wynika prawie bezpośrednio z tego oświadczenia:
^(^x|\1xx)*$
Można zauważyć, że pierwsza iteracja będzie pasować tylko do jednej x
, a każda kolejna iteracja będzie pasowała do ciągu dwóch dłuższych niż poprzednie, dokładnie tak, jak określono. Oznacza to również niezwykle krótki idealny test kwadratowy w perlu:
(1x$_)=~/^(^1|11\1)*$/
Wyrażenie regularne może być dalej uogólnione, aby pasowało do dowolnej n -gonal długości:
Liczby trójkątne:
^(^x|\1x{1})*$
Liczby kwadratowe:
^(^x|\1x{2})*$
Liczby pięciokątne:
^(^x|\1x{3})*$
Liczby sześciokątne:
^(^x|\1x{4})*$
itp.
f (n) = n 3
Przechodząc do n 3 , jeszcze raz analizując funkcję różnicy naprzód:
Może nie być od razu widoczne, jak to zaimplementować, dlatego badamy również drugą funkcję różnicy:
Tak więc funkcja różnicy do przodu nie zwiększa się o stałą, ale raczej o wartość liniową. Fajnie, że początkowa („ -1 ”) wartość D f 2 wynosi zero, co oszczędza inicjalizację przy drugiej iteracji. Wynikowe wyrażenie regularne jest następujące:
^((^|\2x{6})(^x|\1))*$
Pierwsza iteracja będzie pasować do 1 , tak jak poprzednio, druga będzie pasować do ciągu 6 dłuższych ( 7 ), trzecia będzie pasowała do ciągu 12 dłuższych ( 19 ) itp.
f (n) = n 4
Funkcja różnicy w przód dla n 4 :
Druga funkcja różnicy w przód:
Trzecia funkcja różnicy w przód:
To brzydkie. Początkowe wartości D f 2 i D f 3 są niezerowe, odpowiednio 2 i 12 , co należy uwzględnić. Prawdopodobnie już zorientowałeś się, że wyrażenie regularne będzie zgodne z następującym wzorcem:
^((^|\2\3{b})(^|\3x{a})(^x|\1))*$
Ponieważ D f 3 podczas drugiej iteracji musi mieć długość 12 , a to koniecznie 12 . Ponieważ jednak zwiększa się o 24 w każdym członie, kolejne głębsze zagnieżdżenie musi dwukrotnie użyć poprzedniej wartości, co oznacza b = 2 . Ostatnią rzeczą do zrobienia jest zainicjowanie D f 2 . Ponieważ D f 2 wpływa bezpośrednio na D f , co ostatecznie chcemy dopasować, jego wartość można zainicjować, wstawiając odpowiedni atom bezpośrednio do wyrażenia regularnego, w tym przypadku (^|xx)
. Ostateczne wyrażenie regularne staje się wtedy:
^((^|xx)(^|\3\4{2})(^|\4x{12})(^x|\1))*$
Wyższe zamówienia
Wielomian piątego rzędu można dopasować za pomocą następującego wyrażenia regularnego:
^((^|\2\3{c})(^|\3\4{b})(^|\4x{a})(^x|\1))*$
f (n) = n 5 jest dość łatwym ćwiczeniem, ponieważ początkowe wartości zarówno dla drugiej, jak i czwartej funkcji różnicy w przód wynoszą zero:
^((^|\2\3)(^|\3\4{4})(^|\4x{30})(^x|\1))*$
Dla wielomianów sześciu rzędów:
^((^|\2\3{d})(^|\3\4{c})(^|\4\5{b})(^|\5x{a})(^x|\1))*$
W przypadku wielomianów siódmego rzędu:
^((^|\2\3{e})(^|\3\4{d})(^|\4\5{c})(^|\5\6{b})(^|\6x{a})(^x|\1))*$
itp.
Zauważ, że nie wszystkie wielomiany można dopasować dokładnie w ten sposób, jeśli którykolwiek z niezbędnych współczynników nie jest liczbą całkowitą. Na przykład n 6 wymaga, aby a = 60 , b = 8 , a c = 3/2 . Można to obejść, w tym przypadku:
^((^|xx)(^|\3\6\7{2})(^|\4\5)(^|\5\6{2})(^|\6\7{6})(^|\7x{60})(^x|\1))*$
Tutaj zmieniłem b na 6 , a c na 2 , które mają ten sam produkt, co wyżej podane wartości. Ważne jest, aby produkt się nie zmieniał, ponieważ · b · c ·… kontroluje funkcję stałej różnicy, która dla wielomianu szóstego rzędu to D f 6 . Obecne są dwa atomy inicjujące: jeden do inicjalizacji D f do 2 , jak w przypadku n 4 , a drugi do inicjalizacji funkcji piątej różnicy do 360 , przy jednoczesnym dodaniu brakujących dwóch z b .