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 с 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