Siatkówka , 66 63 45 43 36 bajtów
^()(\1(?<1>.\1))+(\1(.(?(4).\4)))*$
Pomimo tytułu Retina, jest to zwykły regex .NET, który akceptuje jednoargumentowe przedstawienie liczb Loeschiana.
Wejścia 999 i 1000 zajmują znacznie mniej niż sekundę.
Wypróbuj online! (Pierwszy wiersz włącza pakiet testowy oddzielony od linii, a kolejne dwa zajmują się konwersją na unary dla wygody).
Wyjaśnienie
Rozwiązanie opiera się na klasyfikacji, według której dane wejściowe można zapisać jako i*i + j*(i + j)dodatnie ii nieujemne j(ponieważ nie musimy obsługiwać danych wejściowych 0), i n*njest to tylko suma pierwszych nnieparzystych liczb całkowitych. Gra w golfa była ciekawym ćwiczeniem w referencjach.
„Odwołanie do przodu” ma miejsce, gdy umieścisz odsyłacz wsteczny w grupie, do której się odnosi. Oczywiście to nie działa, gdy grupa jest używana za pierwszym razem, ponieważ nie ma jeszcze żadnych odnośników, ale jeśli umieścisz to w pętli, wówczas odniesienie wsteczne pobierze za każdym razem poprzednią iterację. To z kolei pozwala budować większe przechwytywanie z każdą iteracją. Może to być wykorzystane do stworzenia bardzo zwartych wzorów dla takich rzeczy, jak liczby trójkątne, kwadraty i liczby Fibonacciego.
Jako przykład, wykorzystując fakt, że kwadraty są tylko sumami pierwszych nnieparzystych liczb całkowitych, możemy dopasować kwadratowe dane wejściowe w następujący sposób:
(^.|..\1)+$
Przy pierwszej iteracji ..\1nie może działać, ponieważ \1nie ma jeszcze wartości. Zaczniemy więc od ^.uchwycenia pojedynczej postaci w grupie 1. W kolejnych iteracjach ^.nie pasuje już z powodu zakotwiczenia, ale teraz ..\1jest poprawny. Dopasowuje dwa znaki więcej niż w poprzedniej iteracji i aktualizuje przechwytywanie. W ten sposób dopasowujemy rosnące liczby nieparzyste, uzyskując kwadrat po każdej iteracji.
Niestety nie możemy obecnie korzystać z tej techniki. Po dopasowaniu i*imusimy również uzyskać i, abyśmy mogli go pomnożyć j. Prostym (ale długim) sposobem na zrobienie tego jest skorzystanie z faktu, że dopasowywanie i*iwymaga iiteracji, aby uchwycić irzeczy w grupie 1. Możemy teraz użyć grup bilansujących, aby to wyodrębnić i, ale tak jak powiedziałem, jest to drogie.
Zamiast tego wymyśliłem inny sposób na zapisanie tej „sumy kolejnych nieparzystych liczb całkowitych”, która daje również igrupę przechwytującą na końcu. Oczywiście ita nieparzysta liczba jest po prostu 2i-1. To daje nam sposób na zwiększenie referencji do przodu tylko o 1 na każdej iteracji. To jest ta część:
^()(\1(?<1>.\1))+
To ()po prostu popycha puste przechwytywanie do grupy 1(inicjowanie ido 0). Jest to prawie równoważne z ^.|powyższym prostym rozwiązaniem, ale użycie |w tym przypadku byłoby nieco trudniejsze.
Następnie mamy główną pętlę (\1(?<1>.\1)). \1dopasowuje poprzednie i, (?<1>.\1)a następnie aktualizuje grupę za 1pomocą i+1. Jeśli chodzi o nowe i , właśnie dopasowaliśmy 2i-1postacie. Właśnie tego potrzebujemy.
Kiedy skończyliśmy, dopasowaliśmy trochę kwadratu, i*ia grupa 1nadal trzyma ipostacie.
Druga część jest bliższa prostemu dopasowaniu do kwadratu, który pokazałem powyżej. Zignorujmy na razie odwołanie do 1:
(.(?(4).\1))*
Jest to w zasadzie to samo co (^.|..\4)*, z tym wyjątkiem, że nie możemy z nich skorzystać, ^ponieważ nie jesteśmy na początku łańcucha. Zamiast tego używamy warunkowego, aby dopasować dodatkowe .\1tylko wtedy, gdy już korzystaliśmy z grupy 4. Ale w rzeczywistości jest dokładnie tak samo. To nam daje j*j.
Brakuje tylko j*iterminu. Łączymy to z j*jfaktem, że j*jobliczenia wciąż wymagają jiteracji. Więc dla każdej iteracji przesuwamy kursor io \1. Musimy tylko upewnić się, że nie zapisujesz tego w grupie 4, ponieważ byłoby to bałaganem przy dopasowywaniu kolejnych liczb nieparzystych. W ten sposób dochodzimy do:
(\1(.(?(4).\1)))*