Python 2, 338 326 323 321 310 306 297 293 290 289 280 279 266 264 259 237 230 229 226 223 222 220 219 217 ( 260 238 231 228 225 223 221 220 218 con 0 estado de salida)
exec'''s=raw_input()
S=[M-s.rfind(c,0,M)for M,c in enumerate(s)]
k=0
j=x=%s
while k<=M+x:
if S[k]>j<W[j]or S[k]==W[j]:
k+=1;j+=1;T+=[j]
if j-L>x:print s[k-j:k];z
else:j=T[j]
'''*2%('-1;T=[0];W=S;L=M',0)
print'No!'
El algoritmo es una variación de KMP, utilizando una prueba basada en índices para la coincidencia de caracteres. La idea básica es que si obtenemos un desajuste en la posición, X[i]
entonces podemos recurrir al siguiente lugar posible para una coincidencia de acuerdo con el sufijo más largo X[:i]
que sea isomorfo a un prefijo de X
.
Trabajando de izquierda a derecha, asignamos a cada carácter un índice igual a la distancia a la ocurrencia anterior más reciente de ese carácter, o si no hay una ocurrencia previa, tomamos la longitud del prefijo de cadena actual. Por ejemplo:
MISSISSIPPI
12313213913
Para probar si dos caracteres coinciden, comparamos los índices, ajustándolos apropiadamente para los índices que son mayores que la longitud de la (sub) cadena actual.
El algoritmo KMP se simplifica un poco, ya que no podemos obtener una falta de coincidencia en el primer carácter.
Este programa genera la primera coincidencia si existe. Utilizo un error de tiempo de ejecución para salir en caso de una coincidencia, pero el código se puede modificar fácilmente para salir limpiamente a costa de algunos bytes.
Nota: Para los índices de computación, podemos usar str.rfind
(a diferencia de mi enfoque anterior usando un diccionario) y aún tener una complejidad lineal, suponiendo que str.rfind
comience a buscar desde el final (que parece la única opción de implementación sensata), para cada carácter del alfabeto , nunca tenemos que atravesar la misma parte de la cadena dos veces, por lo que hay un límite superior de (tamaño del alfabeto) * (tamaño de la cadena) comparaciones.
Dado que el código se ofuscó bastante en el curso de golf, aquí hay una solución anterior (293 bytes) que es un poco más fácil de leer:
e=lambda a:a>i<W[i]or a==W[i]
exec('s=raw_input();S=[];p={};M=i=0\nfor c in s:S+=[M-p.get(c,-1)];p[c]=M;M+=1\nW=S;L=M;'*2)[:-9]
T=[0]*L
k=1
while~k+L:
if e(W[k]):i+=1;k+=1;T[k]=i
else:i=T[i]
m=i=0
while m+i<M:
if e(S[m+i]):
if~-L==i:print s[m:m+L];z
i+=1
else:m+=i-T[i];i=T[i]
print'No!'
La e
función prueba la equivalencia de caracteres. La exec
declaración asigna índices y realiza algunas inicializaciones variables. El primer bucle procesa los X
valores de retroceso y el segundo bucle realiza la búsqueda de cadenas.
Actualización: Aquí hay una versión que sale limpiamente, a costa de un byte:
r='No!'
exec'''s=raw_input()
S=[M-s.rfind(c,0,M)for M,c in enumerate(s)]
k=0
j=x=%s
while k<=M+x:
if S[k]>j<W[j]or S[k]==W[j]:
k+=1;j+=1;T+=[j]
if j-L>x:r=k=s[k-j:k]
else:j=T[j]
'''*2%('-1;T=[0];W=S;L=M',0)
print r