Regex (ECMAScript), 131 bayt
Deadcode sayesinde en az -12 bayt (sohbet halinde)
(?=((xx+)(?=\2+$)|x+)+)(?=((x*?)(?=\1*$)(?=(\4xx+?)(\5*(?!(xx+)\7+$)\5)?$)(?=((x*)(?=\5\9*$)x)(\8*)$)x*(?=(?=\5$)\1|\5\10)x)+)\10|x
Çevrimiçi deneyin!
Çıktı eşleşmenin uzunluğu.
ECMAScript regex'leri bir şeyi saymayı oldukça zorlaştırır. Bir döngü dışında tanımlanmış herhangi bir backref, döngü sırasında sabit olacaktır, bir döngü içinde tanımlanmış herhangi bir backref, döngü sırasında sıfırlanacaktır. Bu nedenle, döngü yinelemeler arasında durumu taşımanın tek yolu, geçerli eşleşme konumunu kullanmaktır. Bu tek bir tamsayı ve sadece azaltabilir (peki, pozisyon artar, ancak kuyruğun uzunluğu azalır, ve matematik yapabileceğimiz şey budur).
Bu kısıtlamalar göz önüne alındığında, sadece kopya sayısı saymak imkansız görünüyor. Bunun yerine, alıcıyı hesaplamak için Euler formülünü kullanıyoruz .
İşte sözde kodda nasıl göründüğü:
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
Bununla ilgili iki şüpheli şey var.
Birincisi, girişi yalnızca mevcut üründen kurtarmıyoruz, bu durumda girdinin ana faktörlerine nasıl ulaşabiliriz? İşin püf noktası (N - (N / P)), N ile aynı asal faktörleri> P ile aynıdır. Yeni asal faktörler <P kazanabilir, ancak bunları yine de göz ardı ediyoruz. Bunun sadece işe yaradığını, çünkü en küçükten en büyüğe doğru asal çarpanları yinelememizin, diğer yoldan başarısız olmanın yol açacağını unutmayın.
İkincisi, döngü yinelemelerinde iki sayıyı hatırlamamız gerekir (P ve N, Z sabit olduğundan beri sayılmaz) ve sadece bunun imkansız olduğunu söyledim! Neyse ki, bu iki sayıyı tek bir seferde çevirebiliriz. Döngünün başlangıcında, N'nin her zaman Z'nin bir katı olacağına, P'nin de her zaman Z'den küçük olacağına dikkat edin. Bu nedenle, N + P'yi sadece hatırlayabilir ve P'yi bir modulo ile ayıklayabiliriz.
İşte biraz daha ayrıntılı sözde kodu:
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
Ve burada yorumlanmış regex:
# \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
Ve bir bonus olarak…
Regex (ECMAScript 2018, maç sayısı), 23 bayt
x(?<!^\1*(?=\1*$)(x+x))
Çevrimiçi deneyin!
Çıktı, eşleşme sayısıdır. ECMAScript 2018, değişken uzunluktaki geriye dönük gösterimi (sağdan sola değerlendirilir) sunar;
Bunun bağımsız olarak Leaky Nun'un Retina çözümü tarafından kullanılan aynı yöntem olduğu ve regex'in aynı uzunluktaki ( ve değiştirilebilir ) olduğu ortaya çıktı. Buradan ayrılıyorum, çünkü bu yöntemin ECMAScript 2018'de (ve sadece .NET'te) çalışması ilginç olabilir.
# 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