Regex (ECMAScript), 276 205 201 193 189 octets
La comparaison des multiplicités (exposants) de différents facteurs premiers est un problème intéressant à résoudre avec les expressions rationnelles ECMAScript - le manque de références inverses qui persistent à travers les itérations d'une boucle fait qu'il est difficile de compter n'importe quoi. Même s'il est possible de compter le trait numérique en question, une approche plus indirecte permet souvent un meilleur golf.
Comme pour mes autres publications sur les expressions rationnelles ECMA, je vais donner un avertissement de spoiler: je recommande fortement d'apprendre à résoudre des problèmes mathématiques unaires dans les expressions régulières ECMAScript. Ce fut un voyage fascinant pour moi, et je ne veux pas le gâter pour quiconque pourrait vouloir l'essayer lui-même, en particulier ceux qui s'intéressent à la théorie des nombres. Voir ce post précédent pour une liste des problèmes recommandés consécutivement marqués de spoiler à résoudre un par un.
Alors ne lisez pas plus loin si vous ne voulez pas que la magie regex unaire avancée soit gâtée pour vous . Si vous voulez essayer de découvrir cette magie vous-même, je vous recommande vivement de commencer par résoudre certains problèmes dans les expressions rationnelles ECMAScript, comme indiqué dans cet article lié ci-dessus.
La charge utile principale d'une expression régulière que j'ai développée précédemment s'est avérée très applicable à ce défi. C'est l' expression rationnelle qui trouve le ou les nombres premiers de la multiplicité la plus élevée . Ma première solution a été très longue, et je l'ai ensuite étudiée par étapes, la réécrivant d' abord pour utiliser l'antichambre moléculaire , puis la portant à nouveau sur ECMAScript en utilisant une technique avancée pour contourner le manque d'anticipation moléculaire , puis jouer au golf pour être beaucoup plus petit que la solution ECMAScript originale.
La partie de cette expression rationnelle qui s'applique à ce problème est la première étape, qui trouve Q, le plus petit facteur de N qui partage tous ses facteurs premiers. Une fois que nous avons ce nombre, tout ce que nous avons à faire pour montrer que N est un "nombre d'exposants constants" est de diviser N par Q jusqu'à ce que nous ne puissions plus; si le résultat est 1, tous les nombres premiers sont de multiplicité égale.
Après avoir soumis une réponse en utilisant mon algorithme développé précédemment pour trouver Q, je me suis rendu compte qu'il pouvait être calculé d'une manière entièrement différente: Trouver le plus grand facteur sans carré de N (en utilisant le même algorithme que mon expression rationnelle de Carmichael ). Il s'avère que cela ne pose aucune difficulté * en termes de contournement du manque d'anticipation moléculaire et de recherche de longueur variable (pas besoin de recourir à la technique avancée précédemment utilisée), et est 64 octets plus court! De plus, cela élimine la complexité du traitement du N sans carré et du N premier comme différents cas spéciaux, en laissant tomber 7 autres octets de cette solution.
(Il reste encore d'autres problèmes qui nécessitent la technique avancée précédemment utilisée ici pour jouer au golf le calcul de Q, mais actuellement aucun d'entre eux n'est représenté par mes messages PPCG.)
Je mets le test de multiplicité avant le test des nombres premiers consécutifs car ce dernier est beaucoup plus lent; mettre des tests qui peuvent échouer plus rapidement en premier accélère l'expression régulière pour une entrée uniformément distribuée. Il est également préférable de mettre le golf en premier, car il utilise plus de références arrières (qui coûteraient plus cher si elles étaient à deux chiffres).
J'ai pu supprimer 4 octets de cette expression régulière (193 → 189) en utilisant une astuce trouvée par Grimy qui peut encore raccourcir la division dans le cas où le quotient est garanti supérieur ou égal au diviseur.
^(?=(|(x+)\2*(?=\2$))((?=(xx+?)\4*$)(?=(x+)(\5+$))\6(?!\4*$))*x$)(?=.*$\2|((?=((x*)(?=\2\9+$)x)(\8*$))\10)*x$)(?!(((x+)(?=\13+$)(x+))(?!\12+$)(x+))\11*(?=\11$)(?!(\15\14?)?((xx+)\18+|x?)$))
Essayez-le en ligne!
# For the purposes of these comments, the input number = N.
^
# Assert that all of N's prime factors are of equal multiplicity
# Step 1: Find Q, the largest square-free factor of N (which will also be the smallest
# factor of N that has all the same prime factors as N) and put it in \2.
# If N is square-free, \2 will be unset.
(?=
# Search through all factors of N, from largest to smallest, searching for one that
# satisfies the desired property. The first factor tried will be N itself, for which
# \2 will be unset.
(|(x+)\2*(?=\2$)) # for factors < N: \2 = factor of N; tail = \2
# Assert that tail is square-free (its prime factors all have single multiplicity)
(
(?=(xx+?)\4*$) # \4 = smallest prime factor of tail
(?=(x+)(\5+$)) # \5 = tail / \4 (implicitly); \6 = tool to make tail = \5
\6 # tail = \5
(?!\4*$) # Assert that tail is no longer divisible by \4, i.e. that that
# prime factor was of exactly single multiplicity.
)*x$
)
# Step 2: Require that either \2 is unset, or that the result of repeatedly
# dividing tail by \2 is 1.
(?=
.*$\2
|
(
# In the following division calculation, we can skip the test for divisibility
# by \2-1 because it's guaranteed that \2 <= \8. As a result, we did not need to
# capture \2-1 above, and can use a better-golfed form of the division.
(?=
( # \8 = tail / \2
(x*) # \9 = \8-1
(?=\2\9+$)
x
)
(\8*$) # \10 = tool to make tail = \8
)
\10 # tail = \8
)*
x$ # Require that the end result is 1
)
# Assert that there exists no trio of prime numbers such that N is divisible by the
# smallest and largest prime but not the middle prime.
(?!
( # \11 = a factor of N
( # \12 = a non-factor of N between \11 and \13
(x+)(?=\13+$) # \13 = a factor of N smaller than \11
(x+) # \14 = tool (with \15) to make tail = \13
)
(?!\12+$)
(x+) # \15 = tool to make tail = \12
)
\11*(?=\11$) # tail = \11
# Assert that \11, \12, and \13 are all prime
(?!
(\15\14?)? # tail = either \11, \12, or \13
((xx+)\18+|x?)$
)
)
* Il est toujours plus propre avec l'anticipation moléculaire, sans cas particulier pour N étant sans carré. Cela laisse tomber 6 octets, ce qui donne une solution de 195 187 183 octets :
^(?=(?*(x+))\1*(?=\1$)((?=(xx+?)\3*$)(?=(x+)(\4+$))\5(?!\3*$))*x$)(?=((?=((x*)(?=\1\8+$)x)(\7*$))\9)*x$)(?!(((x+)(?=\12+$)(x+))(?!\11+$)(x+))\10*(?=\10$)(?!(\14\13?)?((xx+)\17+|x?)$))
# For the purposes of these comments, the input number = N.
^
# Assert that all of N's prime factors are of equal multiplicity
# Step 1: Find Q, the largest square-free factor of N (which will also be the smallest
# factor of N that has all the same prime factors as N) and put it in \1.
(?=
(?*(x+)) # \1 = proposed factor of N
\1*(?=\1$) # Assert that \1 is a factor of N; tail = \1
# Assert that tail is square-free (its prime factors all have single multiplicity)
(
(?=(xx+?)\3*$) # \3 = smallest prime factor of tail
(?=(x+)(\4+$)) # \4 = tail / \3 (implicitly); \5 = tool to make tail = \4
\5 # tail = \4
(?!\3*$) # Assert that tail is no longer divisible by \3, i.e. that that
# prime factor was of exactly single multiplicity.
)*x$
)
# Step 2: Require that the result of repeatedly dividing tail by \1 is 1.
(?=
(
# In the following division calculation, we can skip the test for divisibility
# by \1-1 because it's guaranteed that \2 <= \8. As a result, we did not need to
# capture \1-1 above, and can use a better-golfed form of the division.
(?=
( # \7 = tail / \1
(x*) # \8 = \7-1
(?=\1\8+$)
x
)
(\7*$) # \9 = tool to make tail = \7
)
\9 # tail = \7
)*
x$ # Require that the end result is 1
)
# Assert that there exists no trio of prime numbers such that N is divisible by the
# smallest and largest prime but not the middle prime.
(?!
( # \10 = a factor of N
( # \11 = a non-factor of N between \10 and \12
(x+)(?=\12+$) # \12 = a factor of N smaller than \10
(x+) # \13 = tool (with \14) to make tail = \12
)
(?!\11+$)
(x+) # \14 = tool to make tail = \11
)
\10*(?=\10$) # tail = \10
# Assert that \10, \11, and \12 are all prime
(?!
(\14\13?)? # tail = either \10, \11, or \12
((xx+)\17+|x?)$
)
)
Ici, il est porté sur une apparence de longueur variable:
Regex (ECMAScript 2018), 198 195 194 186 182 octets
^(?=(x+)(?=\1*$)(?<=^x((?<!^\5*)\3(?<=(^\4+)(x+))(?<=^\5*(x+?x)))*))((?=((x*)(?=\1\8+$)x)(\7*$))\9)*x$(?<!(?!(\14\16?)?((xx+)\12+|x?)$)(?<=^\13+)((x+)(?<!^\15+)((x+)(?<=^\17+)(x+))))
Essayez-le en ligne!
# For the purposes of these comments, the input number = N.
^
# Assert that all of N's prime factors are of equal multiplicity
# Step 1: Find Q, the largest square-free factor of N (which will also be the smallest
# factor of N that has all the same prime factors as N) and put it in \1.
(?=
(x+)(?=\1*$) # \1 = factor of N; head = \1
(?<= # This is evaluated right-to-left, so please read bottom to top.
^x
(
(?<!^\5*) # Assert that head is no longer divisible by \6, i.e. that
# that prime factor was of exactly single multiplicity.
\3 # head = \4
(?<=(^\4+)(x+)) # \4 = head / \5 (implicitly); \3 = tool to make head = \4
(?<=^\5*(x+?x)) # \5 = smallest prime factor of head
)*
)
)
# Step 2: Require that the result of repeatedly dividing tail by \1 is 1.
(
# In the following division calculation, we can skip the test for divisibility
# by \1-1 because it's guaranteed that \2 <= \8. As a result, we did not need to
# capture \1-1 above, and can use a better-golfed form of the division.
(?=
( # \7 = tail / \1
(x*) # \8 = \7-1
(?=\1\8+$)
x
)
(\7*$) # \9 = tool to make tail = \7
)
\9 # tail = \7
)*
x$ # Require that the end result is 1
# Assert that there exists no trio of prime numbers such that N is divisible by the
# smallest and largest prime but not the middle prime.
# This is evaluated right-to-left, so please read bottom to top, but switch back to
# reading top to bottom at the negative lookahead.
(?<!
# Assert that \13, \15, and \17 are all prime.
(?!
(\14\16?)? # tail = either \13, \15, or \17
((xx+)\12+|x?)$
)
(?<=^\13+)
( # tail = \13
(x+) # \14 = tool to make tail = \15
(?<!^\15+)
(
(x+) # \16 = tool (with \14) to make tail = \17
(?<=^\17+)(x+) # \17 = a factor of N smaller than \13
) # \15 = a non-factor of N between \13 and \17
) # \13 = a factor of N
)