Regex (ECMAScript lezzet), 392 358 328 224 206 165 bayt
Fibonacci sayılarını ECMAScript regex (unary) ile eşleştirmek için uygulanması gereken teknikler, çoğu regex tatında en iyi şekilde yapılmasından çok uzaktır. Ileri / iç içe geçmiş referansların veya özyinelemelerin olmaması, toplam bir şeyi doğrudan saymanın veya sürdürmenin imkansız olduğu anlamına gelir. Bakış açısının eksikliği, çalışmak için yeterli alana sahip olmanın bile sıkıntı yaratmasını güçleştiriyor.
Pek çok soruna tamamen farklı bir bakış açısıyla yaklaşılmalı ve bazı önemli içgörüler gelinceye kadar çözülemez görünmektedir. Çalıştığınız sayıların hangi matematiksel özelliklerinin, belirli bir problemi çözülebilir hale getirmek için kullanılabileceğini bulmakta çok daha geniş bir ağ oluşturmaya zorlar.
Mart 2014'te Fibonacci sayıları için olan bu oldu. Vikipedi sayfasına bakarken, başlangıçta bir yöntem bulamamıştım, ancak belirli bir özellik titizlikle yakın görünüyordu. Sonra matematikçi teukon , bu özelliği bir başkasıyla birlikte kullanmanın mümkün olabileceğini açıkça belirten bir yöntem belirledi . Rejimi inşa etmek konusunda isteksizdi. Devam edip yaptığım tepkisi:
Çılgınsın! ... bunu yapabileceğini düşündüm.
Diğer ECMAScript unary matematik regex gönderilerimde olduğu gibi, bir uyarı vereceğim : ECMAScript regex'te unary matematiksel problemlerin nasıl çözüleceğini öğrenmenizi şiddetle tavsiye ediyorum. Benim için büyüleyici bir yolculuk oldu ve bunu denemek isteyebilecek herhangi biri için, özellikle de sayı teorisine ilgi duyanlar için onu mahvetmek istemiyorum. Birbiri ardına çözmek için art arda spoiler etiketli önerilen sorunların bir listesi için bu yazı bakın .
Öyleyse , eğer sizin için şımarık bazı regex sihrini istemiyorsanız, daha fazla okumayın . Bu sihri kendiniz bulmaya bir göz atmak istiyorsanız, yukarıda belirtilen bağlantıda belirtildiği gibi ECMAScript regex'teki bazı sorunları çözerek başlamanızı şiddetle tavsiye ederim.
Başlangıçta karşılaştığım zorluk: Pozitif x tamsayı bir Fibonacci sayısı, eğer sadece 5x 2 + 4 ve / veya 5x 2 - 4 mükemmel bir kare ise. Ancak bunu bir regex'te hesaplamak için yer yoktur. Çalışmamız gereken tek yer sayının kendisi. Her ikisini de tek başımıza bırakarak 5 ile çarpmak veya kareyi almak için bile yeterli odamız yok .
teukon'un bunu nasıl çözeceğine dair fikri ( aslen burada yayınlanmıştır ):
Düzenli ifade, formun bir dizesiyle sunulur ^x*$
, z uzunluğu olsun. Z'nin elle yapılan ilk birkaç Fibonacci sayısından biri olup olmadığını kontrol edin (21'e kadar yapmalı). Ya değilse:
- Birkaç rakamı oku, b <a'dan büyük olmayacak şekilde.
- 2 , ab ve b 2 oluşturmak için ileriye dönük bakışlar kullanın .
- 5a 2 + 4 veya 5a 2 - 4'ün mükemmel bir kare olduğunu varsayalım (bu nedenle , bazı n'ler için Fn-1 olmalıdır ).
- 5b 2 + 4 veya 5b 2 + 4'ün mükemmel bir kare olduğunu varsayalım (bu nedenle bn Fn olmalıdır ).
- Bu z kontrol = F 2n + 3 veya Z = F olduğu 2n + 4 önceki kullanarak inşa 2 , ab, ve b 2 ve kimlikleri
- F 2-n-1 = F , n 2 + F , n-1 2
- F 2n = (2F , n-1 + K , n ) F , n
Kısacası: Bu kimlikler, verilen bir sayının Fibonacci olduğunu kontrol etme sorununu azaltmamıza izin veriyor, bir çift daha küçük sayının Fibonacci olduğunu kontrol etmek için . Küçük bir cebir, yeterince büyük n (n = 3'ün yapması gereken), F 2n + 3 > F n + 5F n 2 + 4 için her zaman yeterince yer olması gerektiğini gösterecektir.
Ve işte, Regex'te uygulamadan önce bir test olarak yazdığım C'deki algoritma listesi .
Yani daha fazla ado olmadan, işte regex:
^((?=(x*).*(?=x{4}(x{5}(\2{5}))(?=\3*$)\4+$)(|x{4})(?=xx(x*)(\6x?))\5(x(x*))(?=(\8*)\9+$)(?=\8*$\10)\8*(?=(x\2\9+$))(x*)\12)\7\11(\6\11|\12)|x{0,3}|x{5}|x{8}|x{21})$
Çevrimiçi deneyin!
Ve güzel basılmış, yorumladı sürümü:
^(
(?=
(x*) # \2+1 = potential number for which 5*(\2+1)^2 ± 4
# is a perfect square; this is true iff \2+1 is a Fibonacci
# number. Outside the surrounding lookahead block, \2+1 is
# guaranteed to be the largest number for which this is true
# such that \2 + 5*(\2+1)^2 + 4 fits into the main number.
.*
(?= # tail = (\2+1) * (\2+1) * 5 + 4
x{4}
( # \3 = (\2+1) * 5
x{5}
(\2{5}) # \4 = \2 * 5
)
(?=\3*$)
\4+$
)
(|x{4}) # \5 = parity - determined by whether the index of Fibonacci
# number \2+1 is odd or even
(?=xx (x*)(\6 x?)) # \6 = arithmetic mean of (\2+1) * (\2+1) * 5 and \8 * \8,
# divided by 2
# \7 = the other half, including remainder
\5
# require that the current tail is a perfect square
(x(x*)) # \8 = potential square root, which will be the square root
# outside the surrounding lookahead; \9 = \8-1
(?=(\8*)\9+$) # \10 = must be zero for \8 to be a valid square root
(?=\8*$\10)
\8*
(?=(x\2\9+$)) # \11 = result of multiplying \8 * (\2+1), where \8 is larger
(x*)\12 # \12 = \11 / 2; the remainder will always be the same as it
# is in \7, because \8 is odd iff \2+1 is odd
)
\7\11
(
\6\11
|
\12
)
|
x{0,3}|x{5}|x{8}|x{21} # The Fibonacci numbers 0, 1, 2, 3, 5, 8, 21 cannot be handled
# by our main algorithm, so match them here; note, as it so
# happens the main algorithm does match 13, so that doesn't
# need to be handled here.
)$
Çarpma algoritması bu yorumlarda açıklanmıyor, ancak regex posta mesajımın bol olduğu bir paragrafta kısaca açıklanıyor .
Fibonacci regex'in altı farklı versiyonunu koruyordum: en kısa uzunluktan en yüksek hıza kadar cırcırlanan ve yukarıda açıklanan algoritmayı kullanan dört kişi ve farklı, çok daha hızlı fakat çok daha uzun bir algoritma kullanan iki kişi Maç olarak Fibonacci endeksi (buradaki algoritmanın bu yazının kapsamı dışında olduğunu açıklamak, ancak Gist'in orijinal tartışmasında açıklanmıştır ). Bir regex'in pek çok benzer versiyonunu tekrar koruyacağımı sanmıyorum, çünkü o sırada PCRE ve Perl'deki tüm testlerimi, ancak regex motorumu yapıyordum. hız endişelerinin artık o kadar önemli olmadığı kadar hızlıdır (ve belirli bir yapı tıkanıklığa neden oluyorsa, bunun için bir optimizasyon ekleyebilirim) - muhtemelen yine en hızlı ve en kısa bir sürümü yine de koruyabilirim hızda yeterince büyüktü.
"Fibonacci endeksi eksi 1'i bir eşleşme olarak döndür" versiyonu (ağır golf oynamamaktadır):
Çevrimiçi deneyin!
Tüm sürümler, golf optimizasyonlarının tam bir tarihçesiyle github'da:
Fibonacci sayıları eşleştirmek için regex - kısa, hızlı 0.txt (bu yazıdaki gibi en kısa ama en kısa olanı)
Fibonacci sayıları eşleştirmek için regex - kısa, hız 1. fxt
için
regex Fibonacci sayılarını eşleştirmek - kısa, hızlı 3.txt
regex Fibonacci sayılarını eşleştirmek için - fastest.txt
regex Fibonacci sayılarını eşleştirmek için - return index.txt