Retina , 66 63 45 43 36 bayt
^()(\1(?<1>.\1))+(\1(.(?(4).\4)))*$
Retina isminin başlığına rağmen, bu sadece Loeschian sayılarının sıradışı temsilini kabul eden basit bir .NET regex .
999 ve 1000 girişleri bir saniyenin altında bir sürede başarılı.
Çevrimiçi deneyin! (İlk satır, satır besleme ile ayrılmış bir test takımını etkinleştirir ve sonraki iki kolaylık sağlamak için birliğe dönüşmeye özen gösterir.)
açıklama
Çözüm, girdinin hem i*i + j*(i + j)
olumlu i
hem de olumsuz olmayanlar için yazılabileceği sınıflamasına dayanmaktadır j
(çünkü girdiyi tutmak zorunda değiliz 0
) ve bu n*n
sadece ilk n
tek tamsayıların toplamıdır . Golf oynamak, ileriye dönük referanslarda ilginç bir egzersizdi.
Bir "ileri referans", başvurduğu grubun içine bir geri referans yerleştirdiğiniz zamandır. Elbette, grup ilk kez kullanıldığında işe yaramaz, çünkü henüz geri dönülecek bir şey yoktur, ancak bunu bir döngüye koyarsanız, geri dönüş her seferinde önceki yinelemenin yakalanmasını sağlar. Bu da, her yineleme ile daha büyük bir yakalamanızı sağlar. Bu, üçgen sayılar, kareler ve Fibonacci sayıları gibi şeyler için çok kompakt desenler oluşturmak için kullanılabilir.
Örnek olarak, karelerin sadece ilk n
garip tam sayıların toplamı olduğu gerçeğini kullanarak şöyle bir kare girişini eşleştirebiliriz:
(^.|..\1)+$
İlk tekrarda, ..\1
çalışamaz, çünkü \1
henüz bir değeri yok. Böylece ^.
gruba tek bir karakter çekerek başlıyoruz 1
. Sonraki yinelemelerde, ^.
çapa nedeniyle artık eşleşme olmaz, ancak şimdi ..\1
geçerlidir. Önceki yinelemeden iki karakter daha eşleşir ve yakalamayı günceller. Bu şekilde, her bir yinelemeden sonra bir kare alarak, artan tek sayıları eşleştiriyoruz.
Şimdi ne yazık ki, bu tekniği olduğu gibi kullanamıyoruz. Eşleştirdikten sonra i*i
, onu da çarpmamız için i
iyi yapmamız gerekir j
. Bunu yapmanın basit (ama uzun) bir yolu, eşleştirmenin yinelemeler i*i
alması gerçeğini kullanmak i
, böylece i
gruptaki şeyleri yakaladık 1
. Şimdi bunu çıkarmak için dengeleme gruplarını kullanabiliriz i
, ancak dediğim gibi pahalı.
Bunun yerine, i
sonunda bir yakalama grubunda da ortaya çıkan “ardışık tuhaf tam sayıların toplamını” yazmanın farklı bir yolunu buldum . Tabii ki i
tek sayı sadece 2i-1
. Bu bize ileri referansı her bir yinelemede sadece 1 arttırmak için bir yol sunar. Bu kısım:
^()(\1(?<1>.\1))+
Bu ()
sadece boş bir yakalamayı gruba iter 1
(başlangıç i
olarak 0
). Bu, ^.|
yukarıdaki basit çözümde hemen hemen eşdeğerdir , ancak |
bu durumda kullanmak biraz zor olabilir.
O zaman ana döngümüz var (\1(?<1>.\1))
. \1
Bir önceki maçları i
, (?<1>.\1)
sonra grup günceller 1
ile i+1
. Açısından yeni i
, sadece eşleştirdiğimizde 2i-1
karakterleri. Tam olarak ihtiyacımız olan şey.
İşimiz bittiğinde, bir kareyi eşleştirdik i*i
ve grup 1
hala i
karakter tutuyor .
İkinci kısım yukarıda gösterdiğim basit kare eşleşmesine daha yakın. Şimdilik geri tepkisini görmezden gelelim 1
:
(.(?(4).\1))*
Bu temelde aynıdır (^.|..\4)*
, ancak faydalanamayız ^
çünkü ipin başında değiliz. Bunun yerine, .\1
yalnızca grubu kullandığımız zaman ek eşleştirmek için bir koşullu kullanırız 4
. Ama aslında bu tamamen aynı. Bu bize veriyor j*j
.
Eksik olan tek şey j*i
terimdir. Bunu j*j
, j*j
hesaplamanın hala j
yinelemeler alması gerçeğinden yararlanarak birleştiriyoruz . Yani her yineleme için biz de imleci ilerletmek i
ile \1
. Bunu sadece gruba yazmamaya dikkat etmemiz gerekiyor 4
, çünkü bu ardışık tuhaf rakamlarla eşleşir. İşte bu şekilde:
(\1(.(?(4).\1)))*