Пітон 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 з 0 статусом виходу)
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!'
Алгоритм є варіацією KMP, використовуючи тест на основі індексу для відповідності символів. Основна ідея полягає в тому, що якщо ми отримаємо невідповідність у положенні, X[i]то ми можемо повернутися до наступного можливого місця матчу відповідно до найдовшого суфікса, X[:i]який є ізоморфним префіксу X.
Працюючи зліва направо, ми присвоюємо кожному символу індекс, рівний відстані до останнього попереднього виникнення цього символу, або якщо попереднього виникнення немає, то беремо довжину поточного префікса рядка. Наприклад:
MISSISSIPPI
12313213913
Щоб перевірити, чи збігаються два символи, ми порівнюємо індекси, коригуючи відповідним чином для індексів, більших за довжину поточного (під) рядка.
Алгоритм KMP стає дещо спрощеним, оскільки ми не можемо отримати невідповідність першого символу.
Ця програма виводить перший збіг, якщо такий існує. Я використовую помилку під час виконання для виходу у разі збігу, але код можна легко змінити для чистого виходу ціною деяких байтів.
Примітка. Для обчислення індексів ми можемо використовувати str.rfind(на відміну від мого попереднього підходу із використанням словника) і все ще мати лінійну складність, припускаючи, що str.rfindпочинається пошук з кінця (що здається єдиним розумним вибором реалізації) - для кожного символу в алфавіті , нам ніколи не доведеться двічі проходити одну і ту ж частину рядка, тому є верхня межа порівняння (розмір алфавіту) * (розмір рядка).
Оскільки код досить заплутався в ході гольфу, ось попереднє (293 байт) рішення, яке читати трохи простіше:
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!'
У eфункціональних тестах еквівалентність символів. Оператор execпризначає індекси та робить деякі змінні ініціалізації. Перший цикл обробляє Xзворотні значення, а другий цикл здійснює пошук рядків.
Оновлення: Ось версія, яка виходить чисто, ціною одного байта:
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