Regex (ECMAScript), 131 Bytes
Mindestens -12 Bytes dank Deadcode (im Chat)
(?=((xx+)(?=\2+$)|x+)+)(?=((x*?)(?=\1*$)(?=(\4xx+?)(\5*(?!(xx+)\7+$)\5)?$)(?=((x*)(?=\5\9*$)x)(\8*)$)x*(?=(?=\5$)\1|\5\10)x)+)\10|x
Probieren Sie es online!
Die Ausgabe ist die Länge der Übereinstimmung.
ECMAScript-reguläre Ausdrücke machen es extrem schwierig, etwas zu zählen. Jede Backref, die außerhalb einer Schleife definiert ist, bleibt während der Schleife konstant. Jede Backref, die innerhalb einer Schleife definiert ist, wird beim Schleifen zurückgesetzt. Die einzige Möglichkeit, den Status über Schleifeniterationen zu übertragen, ist die Verwendung der aktuellen Übereinstimmungsposition. Das ist eine einzelne Ganzzahl, und sie kann nur abnehmen (nun, die Position nimmt zu, aber die Länge des Schwanzes nimmt ab, und dafür können wir rechnen).
Angesichts dieser Einschränkungen scheint es unmöglich zu sein, Coprime-Zahlen zu zählen. Stattdessen verwenden wir die Euler-Formel , um den Totienten zu berechnen.
So sieht es im Pseudocode aus:
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
Es gibt zwei zweifelhafte Dinge.
Erstens speichern wir nicht die Eingabe, sondern nur das aktuelle Produkt. Wie können wir also zu den Hauptfaktoren der Eingabe gelangen? Der Trick ist, dass (N - (N / P)) die gleichen Primfaktoren> P wie N hat. Es kann neue Primfaktoren <P erhalten, aber wir ignorieren diese trotzdem. Beachten Sie, dass dies nur funktioniert, weil wir die Primfaktoren vom kleinsten zum größten iterieren. Andernfalls würde dies fehlschlagen.
Zweitens müssen wir uns zwei Zahlen über Schleifeniterationen merken (P und N, Z zählen nicht, da sie konstant sind), und ich sagte nur, dass das unmöglich war! Zum Glück können wir diese beiden Zahlen in einer einzigen verwandeln. Beachten Sie, dass zu Beginn der Schleife N immer ein Vielfaches von Z ist, während P immer kleiner als Z ist. Daher können wir uns nur an N + P erinnern und P mit einem Modulo extrahieren.
Hier ist der etwas detailliertere Pseudocode:
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
Und hier ist der kommentierte reguläre Ausdruck:
# \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
Und als Bonus ...
Regex (ECMAScript 2018, Anzahl der Übereinstimmungen), 23 Byte
x(?<!^\1*(?=\1*$)(x+x))
Probieren Sie es online!
Ausgabe ist die Anzahl der Übereinstimmungen. Mit ECMAScript 2018 wird ein Look-Behind mit variabler Länge (von rechts nach links ausgewertet) eingeführt, mit dem einfach alle Zahlen gleichzeitig mit der Eingabe gezählt werden können.
Es stellt sich heraus, dass dies unabhängig von der Retina-Lösung von Leaky Nun die gleiche Methode ist , und der Regex hat sogar die gleiche Länge ( und ist austauschbar ). Ich lasse es hier, weil es von Interesse sein kann, dass diese Methode in ECMAScript 2018 (und nicht nur in .NET) funktioniert.
# 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