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.
^((^|xx)(^|\3\4\4)(^|\4x{12})(^x|\1))*$
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:
^(^x|\1xx)*$
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:
(1x$_)=~/^(^1|11\1)*$/
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:
^((^|\2x{6})(^x|\1))*$
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:
^((^|\2\3{b})(^|\3x{a})(^x|\1))*$
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:
^((^|xx)(^|\3\4{2})(^|\4x{12})(^x|\1))*$
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:
^((^|\2\3)(^|\3\4{4})(^|\4x{30})(^x|\1))*$
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:
^((^|xx)(^|\3\6\7{2})(^|\4\5)(^|\5\6{2})(^|\6\7{6})(^|\7x{60})(^x|\1))*$
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 .