Outra solução
Este é, na minha opinião, um dos problemas mais interessantes do site. Preciso agradecer o código morto por enviá -lo de volta ao topo.
^((^|xx)(^|\3\4\4)(^|\4x{12})(^x|\1))*$
39 bytes , sem condicionais ou asserções ... mais ou menos. As alternâncias, como estão sendo usadas ( ^|
), são um tipo de condicional, de certa forma, para selecionar entre "primeira iteração" e "não primeira iteração".
Esse regex pode ser visto como funcionando aqui: http://regex101.com/r/qA5pK3/1
Tanto o PCRE quanto o Python interpretam o regex corretamente, e também foi testado em Perl até n = 128 , incluindo n 4 -1 e n 4 +1 .
Definições
A técnica geral é a mesma das outras soluções já postadas: defina uma expressão de auto-referência que em cada iteração subsequente corresponda a um comprimento igual ao próximo termo da função de diferença direta, D f , com um quantificador ilimitado ( *
). Uma definição formal da função de diferença progressiva:
Além disso, funções de diferença de ordem superior também podem ser definidas:
Ou, de maneira mais geral:
A função de diferença direta possui muitas propriedades interessantes; é para sequenciar qual é a derivada para funções contínuas. Por exemplo, D f de um n th polinomial ordem irá sempre ser uma N-1 th polinomial fim, e para qualquer i , se D f i = D f i + 1 , então a função F é exponencial, em muito da mesma maneira que a derivada de e x é igual a si mesma. A função discreta mais simples para a qual f = D f é 2 n .
f (n) = n 2
Antes de examinarmos a solução acima, vamos começar com algo um pouco mais fácil: uma regex que corresponde a cadeias cujos comprimentos são um quadrado perfeito. Examinando a função de diferença direta:
Ou seja, a primeira iteração deve corresponder a uma cadeia de comprimento 1 , a segunda uma cadeia de comprimento 3 , a terceira uma cadeia de comprimento 5 , etc. e, em geral, cada iteração deve corresponder a uma cadeia duas mais longa que a anterior. O regex correspondente segue quase diretamente dessa declaração:
^(^x|\1xx)*$
Pode-se observar que a primeira iteração corresponderá apenas a uma x
e cada iteração subsequente corresponderá a uma sequência duas mais longa que a anterior, exatamente como especificado. Isso também implica um teste quadrado perfeito incrivelmente curto em perl:
(1x$_)=~/^(^1|11\1)*$/
Essa regex pode ser generalizada ainda mais para corresponder a qualquer comprimento n- diagonal:
Números triangulares:
^(^x|\1x{1})*$
Números quadrados:
^(^x|\1x{2})*$
Números pentagonais:
^(^x|\1x{3})*$
Números hexagonais:
^(^x|\1x{4})*$
etc.
f (n) = n 3
Passando para n 3 , examinando mais uma vez a função de diferença direta:
Pode não ser imediatamente aparente como implementar isso, portanto examinamos também a segunda função de diferença:
Portanto, a função de diferença para frente não aumenta em uma constante, mas em um valor linear. É bom que o valor inicial (' -1 th') de D f 2 seja zero, o que salva uma inicialização na segunda iteração. A regex resultante é a seguinte:
^((^|\2x{6})(^x|\1))*$
A primeira iteração corresponderá a 1 , como antes, a segunda corresponderá a uma sequência 6 maior ( 7 ), a terceira corresponderá a uma sequência 12 maior ( 19 ), etc.
f (n) = n 4
A função de diferença direta para n 4 :
A segunda função de diferença de avanço:
A terceira função de diferença para a frente:
Agora isso é feio. Os valores iniciais para D f 2 e D f 3 são diferentes de zero, 2 e 12 , respectivamente, que precisarão ser contabilizados. Você provavelmente já descobriu que a regex seguirá esse padrão:
^((^|\2\3{b})(^|\3x{a})(^x|\1))*$
Como o D f 3 deve corresponder a um comprimento de 12 na segunda iteração, a é necessariamente 12 . Mas, como aumenta em 24 a cada termo, o próximo aninhamento mais profundo deve usar seu valor anterior duas vezes, implicando b = 2 . A última coisa a fazer é inicializar o D f 2 . Porque D f 2 influências D que f diretamente, o que é afinal o que queremos corresponder, seu valor pode ser inicializado, inserindo o átomo apropriado diretamente no regex, neste caso (^|xx)
. O regex final passa a ser:
^((^|xx)(^|\3\4{2})(^|\4x{12})(^x|\1))*$
Ordens mais altas
Um polinômio de quinta ordem pode ser correspondido com o seguinte regex:
^((^|\2\3{c})(^|\3\4{b})(^|\4x{a})(^x|\1))*$
f (n) = n 5 é um exercício bastante fácil, pois os valores iniciais para a segunda e a quarta funções de diferença direta são zero:
^((^|\2\3)(^|\3\4{4})(^|\4x{30})(^x|\1))*$
Para seis polinômios de ordem:
^((^|\2\3{d})(^|\3\4{c})(^|\4\5{b})(^|\5x{a})(^x|\1))*$
Para polinômios de sétima ordem:
^((^|\2\3{e})(^|\3\4{d})(^|\4\5{c})(^|\5\6{b})(^|\6x{a})(^x|\1))*$
etc.
Observe que nem todos os polinômios podem ser correspondidos exatamente dessa maneira, se algum dos coeficientes necessários não for um número inteiro. Por exemplo, N 6 requer que a = 60 , b = 8 , e c = 3/2 . Isso pode ser contornado, neste exemplo:
^((^|xx)(^|\3\6\7{2})(^|\4\5)(^|\5\6{2})(^|\6\7{6})(^|\7x{60})(^x|\1))*$
Aqui alterei b para 6 e c para 2 , que têm o mesmo produto que os valores acima mencionados. É importante que o produto não seja alterado, pois a · b · c ·… controla a função de diferença constante, que para um polinômio de sexta ordem é D f 6 . Existem dois átomos de inicialização presentes: uma para inicializar D f a 2 , como com n 4 , e o outro para inicializar a quinta função de diferença para 360 , enquanto ao mesmo tempo, adicionando em dois a falta de b .