正则表达式(ECMAScript),131字节
至少有-12个字节归功于Deadcode(在聊天中)
(?=((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
关于此有两点可疑之处。
首先,我们不保存输入,仅保存当前产品,那么我们如何获取输入的主要因素呢?诀窍在于(N-(N / P))具有与N相同的素数>P。它可能会获得<P的新素数,但是无论如何我们都忽略了这些。请注意,这仅是有效的,因为我们从最小到最大迭代素数,否则将失败。
其次,我们必须记住循环迭代中的两个数字(P和N,因为它是常数,所以Z不计数),我只是说那是不可能的!幸运的是,我们可以将这两个数字合并为一个。请注意,在循环开始时,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解决方案所使用的独立方法,而regex的长度甚至相同(并且可以互换)。我将其留在此处,是因为这种方法可以在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