我的方法需要 O(N) 时间来预处理字符串,然后 O(|ans array|) 来计算答案。
预处理基本上是 KMP 故障表构建部分,在除最后一个字符之外的整个字符串上。("abacab"
在你的例子中)。在之前返回的表中,给定字符串(即5
或'b'
)中最后一个索引的值将是 2。这意味着与以“b”结尾的 AND 匹配的最大前缀是 2。现在,如果您的最后一个字符与前缀 ( 'a'
) 的第三个字符匹配,则您有一个等于前缀的后缀。( "aba"
)
KMP 停在那里。但是你想要所有的比赛。'b'
因此,您需要找到所有前缀为“b”的匹配,而不是以最后一个字符(2 in)结尾的最大匹配。所以你继续进入 KMP 的内部循环,就像上面一样,检查当前以 'b' 结尾的匹配量(可以为零),如果下一个字符等于我们的最后一个字符。
def build_table(pat):
table = [0]*len(pat)
p = 0
for i in range(1,len(pat)):
while p>0 and pat[p]!=pat[i]: #KMP's loop i was talking about
p = table[p-1]
if pat[p]==pat[i]:
table[i] = p+1
p+=1
return table
pat = "abracadabab"
table = build_table(pat[:-1]) #build table for "abracadaba", i.e except last
ans = [] #to store answers
p = len(pat)-1 #last index of table building string i.e 5 or 'b'
while p>0: #the main loop
p = table[p-1]
print(p)
if pat[p]==pat[-1]:
ans.append(p+1)
print(ans)
这对于"abacab"
打印[1,3]
,对于"abracadabra"
它的[1,4]
。将整个长度视为特殊情况。
(请注意我的循环和 KMP 的循环之间的相似之处while
。如果您仍然感到困惑,我强烈建议您彻底阅读/理解 KMP。很容易对此有一个整体的了解,但深入理解对于回答这样的问题非常困难且至关重要.)