Dans le cadre de cette question, considérons uniquement les chaînes qui se composent du caractère x
répété arbitrairement un nombre de fois.
Par exemple:
<empty>
x
xx
xxxxxxxxxxxxxxxx
(Eh bien, en fait, cela ne doit pas nécessairement l'être x
- n'importe quel caractère est correct tant que la chaîne entière n'a qu'un seul type de caractère)
Écrivez une expression régulière dans n'importe quelle saveur d'expression régulière de votre choix pour faire correspondre toutes les chaînes dont la longueur est n 4 pour un entier non négatif n (n> = 0). Par exemple, les chaînes de longueur 0, 1, 16, 81, etc. sont valides; les autres ne sont pas valides.
En raison de la limitation technique, les valeurs de n supérieures à 128 sont difficiles à tester. Cependant, votre regex devrait logiquement fonctionner correctement malgré tout.
Notez que vous n'êtes pas autorisé à exécuter du code arbitraire dans votre regex (pour les utilisateurs Perl). Toute autre syntaxe (look-around, back-reference, etc.) est autorisée.
Veuillez également inclure une brève explication de votre approche du problème.
(Veuillez ne pas coller d'explication de syntaxe de regex générée automatiquement, car elles sont inutiles)
la source
Réponses:
Cette expression (ir) régulière semble fonctionner.
Cette expression régulière est compatible avec les saveurs PCRE, Perl, .NET.
Cela suit essentiellement un "arbre de différence" (je ne sais pas s'il y a un nom propre), qui indique au regex combien de x supplémentaires doivent correspondre pour la quatrième puissance suivante:
\2
,\3
, Les\4
magasins et les mises à jour la différence comme indiqué sur la 2e, 3e et 4e rangs, respectivement.Cette construction peut facilement être étendue pour des puissances supérieures.
Certainement pas une solution élégante, mais cela fonctionne.
la source
Une autre solution
C'est, à mon avis, l'un des problèmes les plus intéressants du site. Je dois remercier deadcode pour l'avoir remonté en haut.
39 octets , sans condition ni assertion ... en quelque sorte. Les alternances, telles qu'elles sont utilisées (
^|
), sont en quelque sorte un conditionnel, pour choisir entre «première itération» et «pas première itération».Cette expression régulière fonctionne ici: http://regex101.com/r/qA5pK3/1
PCRE et Python interprètent correctement l'expression régulière, et elle a également été testée en Perl jusqu'à n = 128 , y compris n 4 -1 et n 4 +1 .
Définitions
La technique générale est la même que dans les autres solutions déjà publiées: définir une expression d'auto-référencement qui, à chaque itération suivante, correspond à une longueur égale au terme suivant de la fonction de différence directe, D f , avec un quantificateur illimité (
*
). Une définition formelle de la fonction de différence directe:De plus, des fonctions de différence d'ordre supérieur peuvent également être définies:
Ou, plus généralement:
La fonction de différence directe a beaucoup de propriétés intéressantes; c'est aux séquences ce qu'est la dérivée aux fonctions continues. Par exemple, D f d'un polynôme d'ordre n sera toujours un polynôme d'ordre n-1 , et pour tout i , si D f i = D f i + 1 , alors la fonction f est exponentielle, de la même manière que la dérivée de e x est égale à elle-même. La fonction discrète la plus simple pour laquelle f = D f est 2 n .
f (n) = n 2
Avant d'examiner la solution ci-dessus, commençons par quelque chose d'un peu plus facile: une expression régulière qui correspond à des chaînes dont les longueurs sont un carré parfait. Examen de la fonction de différence directe:
Cela signifie que la première itération doit correspondre à une chaîne de longueur 1 , la seconde une chaîne de longueur 3 , la troisième une chaîne de longueur 5 , etc., et en général, chaque itération doit correspondre à une chaîne deux plus longue que la précédente. L'expression rationnelle correspondante découle presque directement de cette déclaration:
On peut voir que la première itération correspondra à une seule
x
, et chaque itération suivante correspondra à une chaîne deux plus longue que la précédente, exactement comme spécifié. Cela implique également un test carré parfait incroyablement court en perl:Cette expression régulière peut être encore généralisée pour correspondre à n'importe quelle longueur n- régionale:
Nombres triangulaires:
^(^x|\1x{1})*$
Numéros carrés:
^(^x|\1x{2})*$
Nombres pentagonaux:
^(^x|\1x{3})*$
Nombres hexagonaux:
^(^x|\1x{4})*$
etc.
f (n) = n 3
Passons au n 3 , en examinant à nouveau la fonction de différence directe:
Il n'est peut-être pas immédiatement évident de savoir comment implémenter cela, nous examinons donc également la deuxième fonction de différence:
Ainsi, la fonction de différence vers l'avant n'augmente pas d'une constante, mais plutôt d'une valeur linéaire. C'est bien que la valeur initiale (' -1 th') de D f 2 soit zéro, ce qui enregistre une initialisation à la deuxième itération. Le regex résultant est le suivant:
La première itération correspondra à 1 , comme précédemment, la seconde correspondra à une chaîne 6 plus longue ( 7 ), la troisième correspondra à une chaîne 12 plus longue ( 19 ), etc.
f (n) = n 4
La fonction de différence directe pour n 4 :
La deuxième fonction de différence directe:
La troisième fonction de différence directe:
Maintenant, c'est moche. Les valeurs initiales pour D f 2 et D f 3 sont toutes les deux non nulles, 2 et 12 respectivement, qui devront être prises en compte. Vous avez probablement compris maintenant que l'expression régulière suivra ce modèle:
Parce que le D f 3 doit correspondre à une longueur de 12 à la deuxième itération, a est nécessairement 12 . Mais comme il augmente de 24 à chaque terme, l'imbrication plus profonde suivante doit utiliser sa valeur précédente deux fois, ce qui implique b = 2 . La dernière chose à faire est d'initialiser le D f 2 . Parce que D f 2 influence directement D f , ce qui est finalement ce que nous voulons faire correspondre, sa valeur peut être initialisée en insérant l'atome approprié directement dans l'expression régulière, dans ce cas
(^|xx)
. Le regex final devient alors:Ordres supérieurs
Un polynôme du cinquième ordre peut être mis en correspondance avec l'expression régulière suivante:
^((^|\2\3{c})(^|\3\4{b})(^|\4x{a})(^x|\1))*$
f (n) = n 5 est un exercice assez facile, car les valeurs initiales pour les deuxième et quatrième fonctions de différence directe sont nulles:
Pour six polynômes d'ordre:
^((^|\2\3{d})(^|\3\4{c})(^|\4\5{b})(^|\5x{a})(^x|\1))*$
Pour les polynômes du septième ordre:
^((^|\2\3{e})(^|\3\4{d})(^|\4\5{c})(^|\5\6{b})(^|\6x{a})(^x|\1))*$
etc.
Notez que tous les polynômes ne peuvent pas être appariés exactement de cette manière, si l'un des coefficients nécessaires n'est pas entier. Par exemple, n 6 requiert que a = 60 , b = 8 et c = 3/2 . Cela peut être contourné, dans ce cas:
Ici, j'ai changé b en 6 et c en 2 , qui ont le même produit que les valeurs indiquées ci-dessus. Il est important que le produit ne change pas, car un · b · c · ... contrôle la fonction de différence constante, qui pour un polynôme du sixième ordre est D f 6 . Il y a deux atomes d'initialisation présents: l'un pour initialiser D f à 2 , comme pour n 4 , et l'autre pour initialiser la cinquième fonction de différence à 360 , tout en ajoutant en même temps les deux manquants de b .
la source
Voici une solution qui n'utilise pas de conditionnelles, de références arrières déclarées ou imbriquées, de lookbehind, d'équilibrage de groupes ou de récursivité d'expression régulière. Il utilise uniquement des références et des références arrières standard, qui sont très largement prises en charge. J'ai été inspiré pour opérer dans ces limites en raison de Regex Golf , qui utilise le moteur regex ECMAScript.
Le fonctionnement de cette expression régulière de 50 octets est conceptuellement assez simple et complètement différent de toutes les autres solutions soumises à ce puzzle. Il était surprenant de découvrir que ce type de logique mathématique était exprimable dans une expression régulière.
(Les groupes de capture sont étiquetés au-dessus de l'expression régulière)
L'expression rationnelle peut être généralisée à tout pouvoir simplement en remplaçant le
4
dans{4}
de la puissance désirée.Essayez-le en ligne!
Il fonctionne en divisant à plusieurs reprises la plus petite quatrième puissance d'un nombre premier par laquelle la valeur actuelle est divisible. En tant que tel, le quotient à chaque étape est toujours une quatrième puissance, si la valeur d'origine était une quatrième puissance. Un dernier quotient de 1 indique que la valeur d'origine était bien une quatrième puissance; ceci termine le match. Zéro est également apparié.
Tout d'abord, il utilise un groupe de capture paresseux
\2
pour capturer le plus petit facteur du nombre supérieur à 1. En tant que tel, ce facteur est garanti d'être premier. Par exemple, avec 1296 (6 ^ 4), il capturera initialement\2
= 2.Ensuite, au début d'une boucle répétée 4 fois, il teste pour voir si le nombre courant est divisible par
\2
, avec(?=\2+$)
. La première fois dans cette boucle, ce test est inutile, mais son objectif apparaîtra plus tard.Suivant l' intérieur de cette boucle interne, il utilise le groupe de capture avide
\4
de capturer le plus grand facteur du plus petit nombre que lui - même:(?=(x+)(\4+)$)
. En effet , cela divise le nombre par son plus petit facteur premier,\2
; par exemple, 1296 sera initialement capturé comme\4
= 1296/2 = 648. Notez que la division du nombre actuel par\2
est implicite. Bien qu'il soit possible de diviser explicitement le nombre actuel par un nombre contenu dans un groupe de capture (que je n'ai découvert que quatre jours après la publication de cette réponse), cela ferait une expression régulière plus lente et plus difficile à comprendre, et ce n'est pas nécessaire, car le plus petit facteur d'un nombre supérieur à 1 correspondra toujours à son plus grand facteur plus petit que lui-même (de sorte que leur produit est égal au nombre lui-même).Étant donné que ce type d'expression régulière ne peut que "ronger" la chaîne (la rendant plus petite) en laissant un résultat à la fin de la chaîne, nous devons "déplacer" le résultat de la division à la fin de la chaîne. Cela se fait en capturant le résultat de la soustraction (le nombre actuel moins
\4
), dans le groupe de capture\5
, puis, en dehors de l'anticipation, en faisant correspondre une partie du début du nombre actuel correspondant à\5
. Cela laisse la chaîne non traitée restante à la fin correspondant\4
à la longueur.Maintenant, il revient au début de la boucle intérieure, où il devient évident pourquoi il existe un test de divisibilité par le facteur premier. Nous venons de diviser par le plus petit facteur premier du nombre; si le nombre est encore divisible par ce facteur, cela signifie que le nombre d'origine peut être divisible par la quatrième puissance de ce facteur. La première fois que ce test est effectué, il est inutile, mais les 3 fois suivantes, il détermine si le résultat de la division implicite par
\2
est toujours divisible par\2
. S'il est toujours divisible par\2
au début de chaque itération de la boucle, cela prouve que chaque itération a divisé le nombre par\2
.Dans notre exemple, avec une entrée de 1296, cela se déroulera comme suit:
\2
= 2\4
= 1296/2 = 648\4
= 648/2 = 324\4
= 324/2 = 162\4
= 162/2 = 81Maintenant, l'expression régulière peut revenir en boucle à la première étape; c'est ce que fait la finale
*
. Dans cet exemple, 81 deviendra le nouveau numéro; la prochaine boucle se déroulera comme suit:\2
= 3\4
= 81/3 = 27\4
= 27/3 = 9\4
= 9/3 = 3\4
= 3/3 = 1Il reviendra maintenant à la première étape, avec 1 comme nouveau numéro.
Le nombre 1 ne peut être divisé par aucun nombre premier, ce qui en ferait une non-correspondance
(?=(xx+?)\2+$)
, il quitte donc la boucle de niveau supérieur (celle avec*
à la fin). Il atteint maintenant lex?$
. Cela ne peut correspondre qu'à zéro ou un. Le nombre actuel à ce stade sera 0 ou 1 si et seulement si le nombre d'origine était une quatrième puissance parfaite; si elle est 0 à ce stade, cela signifie que la boucle de niveau supérieur n'a jamais correspondu à rien, et si elle est 1, cela signifie que la boucle de niveau supérieur a divisé une quatrième puissance parfaite jusqu'à ce qu'elle ne soit plus divisible par rien (ou c'était 1 en premier lieu, ce qui signifie que la boucle de niveau supérieur ne correspondait à rien).Il est également possible de résoudre cela en 49 octets en effectuant une division explicite répétée (qui est également généralisée pour toutes les puissances - remplacez la puissance souhaitée moins une dans la
{3}
), mais cette méthode est beaucoup, beaucoup plus lente et une explication de l'algorithme qu'elle utilise dépasse le cadre de cette réponse:Essayez-le en ligne!
la source
((((x+)\5+)\4+)\3+)\2+$
. Le vôtre est également étonnant à sa manière, car je ne peux même pas penser à la façon de faire correspondre un nombre carré sans référence inverse déclarée.(?:)
. Dois-je donc modifier ma réponse pour faire de la version optimisée la principale?Solution
Cette expression régulière est compatible avec les saveurs Java, Perl, PCRE et .NET. Cette expression régulière utilise toute une gamme de fonctionnalités: look-ahead, look-behind et forward-declare back-reference. Les types de référence arrière déclarés à l'avance limitent la compatibilité de cette expression régulière à quelques moteurs.
Explication
Cette solution utilise la dérivation suivante.
En étendant complètement la somme, nous pouvons prouver l'égalité suivante:
Combinons la sommation à gauche:
Soustrayez les 2 équations (équation du haut moins équation du bas) puis combinez les sommations sur le côté gauche, puis simplifiez-la:
Nous obtenons la différence entre les quatrièmes puissances consécutives comme somme de puissance:
Cela signifie que la différence entre les quatrièmes puissances consécutives augmentera de (12n 2 + 2).
Pour faciliter la réflexion, en se référant à l' arbre de différence dans la réponse de Volatility :
Assez de mathématiques. Retour à la solution ci-dessus:
Le 1er groupe de capture maintient une série de nombres impairs pour calculer i 2 comme le montre l'équation.
Précisément, la longueur du 1er groupe de capture sera 0 (inutilisé), 1, 3, 5, 7, ... au fur et à mesure de l'itération de la boucle.
(?<=^x)x
définit la valeur initiale de la série de nombres impairs. Le^
est juste là pour permettre à l'anticipation d'être satisfaite dans la première itération.xx\1
ajoute 2 et avance au nombre impair suivant.Le 2e groupe de capture conserve la série de nombres carrés pour i 2 .
Précisément, la longueur du 2ème groupe de capture sera 0, 1, 4, 9, ... au fur et à mesure que la boucle itère.
^
in(^|\1\2)
définit la valeur initiale de la série de nombres carrés. Et\1\2
ajoute le nombre impair au nombre carré actuel pour le faire passer au nombre carré suivant.Le troisième groupe de capture (en dehors de toute perspective et consommant réellement du texte) correspond à tout le côté droit de l'équation que nous avons dérivée ci-dessus.
^x
in(^x|\3\2{12}xx)
définit la valeur initiale, qui est+ 1
le côté droit de l'équation.\3\2{12}xx
ajoute l'augmentation de la différence (12n 2 + 2) en utilisant n 2 du groupe de capture 2, et correspond à la différence en même temps.Cette disposition est possible car la quantité de texte mise en correspondance dans chaque itération est supérieure ou égale à la quantité de texte nécessaire pour exécuter l'anticipation pour construire n 2 .
la source