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