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 z 0 statusem wyjścia)
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!'
Algorytm jest odmianą KMP, z wykorzystaniem testu indeksowego do dopasowywania znaków. Podstawową ideą jest to, że jeśli otrzymamy niedopasowanie pozycji X[i], możemy wrócić do następnego możliwego miejsca meczu zgodnie z najdłuższym sufiksem, X[:i]który jest izomorficzny do przedrostka X.
Pracując od lewej do prawej, przypisujemy każdemu znakowi indeks równy odległości do ostatniego poprzedniego wystąpienia tego znaku, lub jeśli nie było wcześniejszego wystąpienia, bierzemy długość bieżącego prefiksu łańcucha. Na przykład:
MISSISSIPPI
12313213913
Aby sprawdzić, czy dwa znaki pasują do siebie, porównujemy indeksy, odpowiednio dostosowując indeksy, które są większe niż długość bieżącego (pod) łańcucha.
Algorytm KMP staje się nieco uproszczony, ponieważ nie możemy uzyskać niedopasowania pierwszego znaku.
Ten program generuje pierwsze dopasowanie, jeśli takie istnieje. Używam błędu środowiska wykonawczego, aby wyjść w przypadku dopasowania, ale kod można łatwo zmodyfikować, aby wyjść czysto kosztem niektórych bajtów.
Uwaga: Do obliczania indeksów możemy użyć str.rfind(w przeciwieństwie do mojego wcześniejszego podejścia ze słownikiem) i nadal mieć liniową złożoność, zakładając, że str.rfindzaczyna się wyszukiwanie od końca (co wydaje się jedynym rozsądnym wyborem implementacji) - dla każdego znaku w alfabecie , nigdy nie musimy dwukrotnie przechodzić przez tę samą część łańcucha, więc istnieje górna granica porównań (rozmiar alfabetu) * (rozmiar łańcucha).
Ponieważ kod został dość zaciemniony w trakcie gry w golfa, oto wcześniejsze (293 bajtowe) rozwiązanie, które jest nieco łatwiejsze do odczytania:
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!'
Do etestów czynnościowych równoważności znaków. execInstrukcja przypisuje indeksy i robi pewne zmienne Initialisations. Pierwsza pętla przetwarza Xwartości rezerwowe, a druga pętla wyszukuje ciąg znaków.
Aktualizacja: Oto wersja, która kończy się czysto, kosztem jednego bajtu:
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