正規表現(ECMAScript)、131バイト
Deadcode(チャット)のおかげで少なくとも-12バイト
(?=((xx+)(?=\2+$)|x+)+)(?=((x*?)(?=\1*$)(?=(\4xx+?)(\5*(?!(xx+)\7+$)\5)?$)(?=((x*)(?=\5\9*$)x)(\8*)$)x*(?=(?=\5$)\1|\5\10)x)+)\10|x
オンラインでお試しください!
出力は一致の長さです。
ECMAScriptの正規表現は、数を数えることを非常に困難にします。ループの外部で定義されたbackrefはループ中は一定であり、ループの内部で定義されたbackrefはループ時にリセットされます。したがって、ループの反復間で状態を保持する唯一の方法は、現在の一致位置を使用することです。それは単一の整数であり、減少することしかできません(まあ、位置は増加しますが、尾の長さは減少します。
これらの制限があるため、単純に素数を数えることは不可能に思えます。代わりに、オイラーの公式を使用してトーティエントを計算します。
擬似コードでは次のようになります。
N = input
Z = largest prime factor of N
P = 0
do:
P = smallest number > P that’s a prime factor of N
N = N - (N / P)
while P != Z
return N
これには2つの疑わしい点があります。
まず、入力を保存せず、現在の製品のみを保存します。それでは、入力の素因数にどのようにアクセスできますか?秘Theは、(N-(N / P))がNと同じ素因数を持っていることです。新しい素因数<Pを獲得するかもしれませんが、とにかくそれらを無視します。これが機能するのは、最小から最大まで素因数を反復するためだけであり、他の方法では失敗することに注意してください。
第二に、ループの繰り返し全体で2つの数値を覚えておく必要があります(PとN、Zは定数であるためカウントされません)。ありがたいことに、これら2つの数値を1つの数値に切り替えることができます。ループの開始時に、Nは常にZの倍数になり、Pは常にZ未満になることに注意してください。したがって、N + Pを記憶し、モジュロでPを抽出できます。
次に、もう少し詳細な擬似コードを示します。
N = input
Z = largest prime factor of N
do:
P = N % Z
N = N - P
P = smallest number > P that’s a prime factor of N
N = N - (N / P) + P
while P != Z
return N - Z
そして、コメント付きの正規表現は次のとおりです。
# \1 = largest prime factor of N
# Computed by repeatedly dividing N by its smallest factor
(?= ( (xx+) (?=\2+$) | x+ )+ )
(?=
# Main loop!
(
# \4 = N % \1, N -= \4
(x*?) (?=\1*$)
# \5 = next prime factor of N
(?= (\4xx+?) (\5* (?!(xx+)\7+$) \5)? $ )
# \8 = N / \5, \9 = \8 - 1, \10 = N - \8
(?= ((x*) (?=\5\9*$) x) (\8*) $ )
x*
(?=
# if \5 = \1, break.
(?=\5$) \1
|
# else, N = (\5 - 1) + (N - B)
\5\10
)
x
)+
) \10
ボーナスとして…
正規表現(ECMAScript 2018、一致数)、23バイト
x(?<!^\1*(?=\1*$)(x+x))
オンラインでお試しください!
出力は一致の数です。ECMAScript 2018では、可変長の後読み(右から左に評価)が導入されました。これにより、入力と互いに素なすべての数を単純にカウントすることができます。
これは、独立してLeaky NunのRetinaソリューションで使用されているのと同じ方法であり、正規表現は同じ長さ(および交換可能)でさえあることがわかります。このメソッドがECMAScript 2018(.NETだけでなく)で動作するのは興味深いかもしれないので、ここに残しておきます。
# Implicitly iterate from the input to 0
x # Don’t match 0
(?<! ) # Match iff there is no...
(x+x) # integer >= 2...
(?=\1*$) # that divides the current number...
^\1* # and also divides the input