Otra solución
Este es, en mi opinión, uno de los problemas más interesantes del sitio. Necesito agradecer a deadcode por subirlo de nuevo a la cima.
^((^|xx)(^|\3\4\4)(^|\4x{12})(^x|\1))*$
39 bytes , sin condicionales o afirmaciones ... más o menos. Las alternancias, a medida que se usan ( ^|
), son un tipo de condicional en cierto modo, para seleccionar entre "primera iteración" y "no primera iteración".
Se puede ver que esta expresión regular funciona aquí: http://regex101.com/r/qA5pK3/1
Tanto PCRE como Python interpretan la expresión regular correctamente, y también se ha probado en Perl hasta n = 128 , incluyendo n 4 -1 , y n 4 1 .
Definiciones
La técnica general es la misma que en las otras soluciones ya publicadas: defina una expresión autorreferenciada que en cada iteración posterior coincida con una longitud igual al siguiente término de la función de diferencia directa, D f , con un cuantificador ilimitado ( *
). Una definición formal de la función de diferencia directa:
Además, también se pueden definir funciones de diferencia de orden superior:
O, más generalmente:
La función de diferencia hacia adelante tiene muchas propiedades interesantes; es a secuencias lo que la derivada es a funciones continuas. Por ejemplo, D f de un n º polinomio de orden siempre será un n-1 ésimo polinomio de orden, y para cualquier i , si D f i = D f i + 1 , entonces la función f es exponencial, de la misma manera que la derivada de e x es igual a sí misma. La función discreta más simple para la cual f = D f es 2 n .
f (n) = n 2
Antes de examinar la solución anterior, comencemos con algo un poco más fácil: una expresión regular que coincida con cadenas cuyas longitudes son un cuadrado perfecto. Examinando la función de diferencia directa:
Es decir, la primera iteración debe coincidir con una cadena de longitud 1 , la segunda una cadena de longitud 3 , la tercera una cadena de longitud 5 , etc., y en general, cada iteración debe coincidir con una cadena dos más larga que la anterior. La expresión regular correspondiente se sigue casi directamente de esta declaración:
^(^x|\1xx)*$
Se puede ver que la primera iteración coincidirá solo con una x
, y cada iteración posterior coincidirá con una cadena dos veces más larga que la anterior, exactamente como se especifica. Esto también implica una prueba cuadrada perfecta increíblemente corta en perl:
(1x$_)=~/^(^1|11\1)*$/
Esta expresión regular se puede generalizar aún más para que coincida con cualquier longitud n- gonal:
Números triangulares
^(^x|\1x{1})*$
Números cuadrados:
^(^x|\1x{2})*$
Números pentagonales:
^(^x|\1x{3})*$
Números hexagonales:
^(^x|\1x{4})*$
etc.
f (n) = n 3
Pasando a n 3 , una vez más examinando la función de diferencia hacia adelante:
Es posible que no se vea de inmediato cómo implementar esto, por lo que también examinamos la segunda función de diferencia:
Por lo tanto, la función de diferencia directa no aumenta en una constante, sino en un valor lineal. Es bueno que el valor inicial (' -1 °') de D f 2 sea cero, lo que guarda una inicialización en la segunda iteración. La expresión regular resultante es la siguiente:
^((^|\2x{6})(^x|\1))*$
La primera iteración coincidirá con 1 , como antes, la segunda coincidirá con una cadena 6 más larga ( 7 ), la tercera coincidirá con una cadena 12 más larga ( 19 ), etc.
f (n) = n 4
La función de diferencia directa para n 4 :
La segunda función de diferencia hacia adelante:
La tercera función de diferencia hacia adelante:
Eso sí que es feo. Los valores iniciales para D f 2 y D f 3 son ambos distintos de cero, 2 y 12 respectivamente, que deberán tenerse en cuenta. Probablemente ya se haya dado cuenta de que la expresión regular seguirá este patrón:
^((^|\2\3{b})(^|\3x{a})(^x|\1))*$
Debido a que D f 3 debe coincidir con una longitud de 12 en la segunda iteración, a es necesariamente 12 . Pero debido a que aumenta en 24 cada término, la siguiente anidación más profunda debe usar su valor anterior dos veces, lo que implica b = 2 . Lo último que debe hacer es inicializar el D f 2 . Debido a que D f 2 influye en D f directamente, que en última instancia es lo que queremos igualar, su valor puede inicializarse insertando el átomo apropiado directamente en la expresión regular, en este caso (^|xx)
. La expresión regular final se convierte en:
^((^|xx)(^|\3\4{2})(^|\4x{12})(^x|\1))*$
Órdenes superiores
Un polinomio de quinto orden se puede combinar con la siguiente expresión regular:
^((^|\2\3{c})(^|\3\4{b})(^|\4x{a})(^x|\1))*$
f (n) = n 5 es un ejercicio bastante fácil, ya que los valores iniciales para la segunda y cuarta funciones de diferencia directa son cero:
^((^|\2\3)(^|\3\4{4})(^|\4x{30})(^x|\1))*$
Para polinomios de seis órdenes:
^((^|\2\3{d})(^|\3\4{c})(^|\4\5{b})(^|\5x{a})(^x|\1))*$
Para polinomios de séptimo orden:
^((^|\2\3{e})(^|\3\4{d})(^|\4\5{c})(^|\5\6{b})(^|\6x{a})(^x|\1))*$
etc.
Tenga en cuenta que no todos los polinomios pueden coincidir exactamente de esta manera, si alguno de los coeficientes necesarios no son enteros. Por ejemplo, n 6 requiere que a = 60 , b = 8 , y c = 3/2 . Esto se puede solucionar, en este caso:
^((^|xx)(^|\3\6\7{2})(^|\4\5)(^|\5\6{2})(^|\6\7{6})(^|\7x{60})(^x|\1))*$
Aquí he cambiado de b a 6 y de c a 2 , que tienen el mismo producto que los valores indicados anteriormente. Es importante que el producto no cambie, ya que a · b · c · ... controla la función de diferencia constante, que para un polinomio de sexto orden es D f 6 . Hay dos átomos de inicialización presentes: uno para inicializar D f a 2 , como con n 4 , y el otro para inicializar la función de quinta diferencia a 360 , mientras que al mismo tiempo agrega los dos que faltan de b .