正規表現(ECMAScriptフレーバー)、392 358 328 224 206 165バイト
フィボナッチ数とECMAScript正規表現(単項)を一致させるために必要なテクニックは、他のほとんどの正規表現フレーバーでの最適な方法とはかけ離れています。前方参照/ネストされた後方参照または再帰がないため、実行中の合計を直接カウントしたり保持したりすることはできません。後読みの欠如は、作業するのに十分なスペースを確保することさえしばしば困難になります。
多くの問題は完全に異なる視点からアプローチされなければならず、いくつかの重要な洞察が到来するまで解決できないように思われます。特定の問題を解決するために、使用している数字のどの数学プロパティを使用できるかを見つける際に、はるかに広いネットをキャストする必要があります。
2014年3月に、これがフィボナッチ数に起こりました。ウィキペディアのページを見ると、最初は方法がわかりませんでしたが、特定のプロパティの1つが食欲をそそるほど近くに見えました。次に、数学者のテューコンは、そのプロパティを別のプロパティと一緒に使用して、実行できることを非常に明確にする方法を概説しました。彼は実際に正規表現を構築することに消極的でした。私が先に進んだときの彼の反応:
あなたは狂っている!...あなたはこれをするかもしれないと思った。
私の他のECMAScript単項数学正規表現の投稿と同様に、警告を出します。ECMAScript正規表現の単項数学問題を解決する方法を学ぶことを強くお勧めします。それは私にとって魅力的な旅であり、自分で試してみたいと思う人、特に数論に興味のある人のためにそれを台無しにしたくありません。連続してスポイラーでタグ付けされた推奨される問題のリストについては、その投稿を参照して1つずつ解決してください。
したがって、単項正規表現の魔法を台無しにしたくない場合は、これ以上読み進めないでください。この魔法を自分で理解するためにショットを撮りたい場合は、上記のリンクに記載されているECMAScript正規表現の問題を解決することから始めることを強くお勧めします。
私が最初に直面した課題は:正の整数xは フィボナッチ数である場合にのみ5X場合2 + 4及び/又は5× 2 - 4は完全な方形です。しかし、正規表現でこれを計算する余地はありません。作業しなければならない唯一のスペースは、番号そのものです。5を掛けたり、正方形をとったりすることはできません。
それを解決する方法に関するtueukonのアイデア(元々はここに投稿されました):
正規表現には、形式の文字列が表示され、^x*$
その長さをzとします。zが最初の数個のフィボナッチ数の1つであるかどうかを手動で確認します(最大21個)。そうでない場合:
- bが2a以下になるように、a <bの数個の数値を読み取ります。
- 先読みを使用してa 2、ab、およびb 2を構築します。
- いずれか5Aと主張2 + 4又は図5(a)2 4が完全な正方形(SO Fでなければなりません- N-1 、いくつかのnについて)。
- 5b 2 + 4または5b 2 + 4が完全な正方形であると断定します(bはF nでなければなりません)。
- 以前に作成したa 2、ab、およびb 2、およびID を使用して、z = F 2n + 3またはz = F 2n + 4であることを確認します。
- F 2n-1 = F n 2 + F n-1 2
- F 2n =(2F n-1 + F n)F n
簡単に言えば:これらのIDは、私たちは、一対ことを確認するに与えられた数がフィボナッチであることを確認の問題を軽減することができるように多くの。小さい数字はフィボナッチあります 小さな代数は、十分に大きいn(n = 3で十分)に対して、F 2n + 3 > F n + 5F n 2 + 4であるため、常に十分なスペースがあることを示します。
そして、これが正規表現で実装する前にテストとして書いたCのアルゴリズムのモックアップです。
これ以上苦労することなく、正規表現を次に示します。
^((?=(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})$
オンラインでお試しください!
そして、きれいに印刷されたコメント付きバージョン:
^(
(?=
(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.
)$
乗算アルゴリズムは、これらのコメントでは説明されていませんが、豊富な数の正規表現postの段落で簡単に説明されています。
私はフィボナッチ正規表現の6つの異なるバージョンを維持していました:4つは最短長から最速までラチェットし、上記で説明したアルゴリズムを使用し、他の2つは異なる、より高速ですがはるかに長いアルゴリズムを使用し、実際に返すことができます一致としてのフィボナッチインデックス(ここでのアルゴリズムはこの投稿の範囲を超えていることを説明していますが、元のディスカッションGistで説明されています)。当時、PCREとPerlですべてのテストを行っていたが、正規表現エンジンを使用していたため、非常に類似した正規表現のバージョンを再び維持するとは思わない 速度の懸念がそれほど重要ではないほど十分に高速です(特定の構成要素がボトルネックを引き起こしている場合、最適化を追加できます)。速度が十分に大きかった。
「フィボナッチ指数から1を引いたものをマッチとして返す」バージョン(重度のゴルフではない):
オンラインでお試しください!
すべてのバージョンはgithubにあり、ゴルフの最適化の完全なコミット履歴があります。
フィボナッチ数を照合するための正規表現-短い、速度0.txt(この投稿のように、最短だが最も遅いもの)
フィボナッチ数
を照合するための正規表現-フィボナッチ数を照合するための短い1.speed
正規表現-短い、速度2.txtの正規表現一致するフィボナッチ数-一致するフィボナッチ数の短縮、速度3.txt
正規表現-一致するフィボナッチ数の最速.txt
正規表現-index.txtを返す