我试图在长度为n的字符串中找到等于后缀的前缀数及其长度。它们可以重叠,例如,如果字符串是" abacaba"然后ans是长度为1(a)的{1,3,7}前缀,3是" aba"和整个字符串。前缀" a"等于后缀" a"。前缀" aba"等于后缀" aba"。整个字符串等于后缀。 如果字符串是" aaaaa"然后答案是{1,2,3,4,5}。 " a"," aa"," aaa"," aaaa"," aaaaa"。
我只能在O(n2)中获取每个前缀并与相同的长度后缀进行比较。但有没有更好的算法来解决这个问题?提前致谢
答案 0 :(得分:2)
哈希可以在这里提供帮助
将字符串a1a2a3a4的哈希函数定义为(a1 * 26 ^ 3 + a2 * 26 ^ 2 + a3 * a6 ^ 1 + a4 * 26 ^ 0)%M其中M是大素数
现在在开始时保持两个指针,在结束时保持一个指针。在每次迭代时向前移动开始指针并计算前缀的哈希值,直到开始并在每次迭代时向后移动结束指针并计算后缀的哈希值,如果哈希值相等则字符串相等。
hash_st = 0
hash_ed = 0
st = 0
ed = len(s)-1
while st ! = len(s) - 1:
hash_st = (hash_st*(26) + ascii_val(s[st])) % M
hash_ed = (ascii_val(s[ed]) * (26^st) + hash_ed) % M
if hash_st == hash_ed:
add_to_result(st)
答案 1 :(得分:2)
我的方法需要O(N)时间来预处理字符串,然后O(| ans array |)来计算答案。
预处理基本上是KMP故障表构建部分,除了最后一个字符之外的整个字符串。 (示例中为"abacab"
)。在之前返回的表中,给定字符串中最后一个索引的值(即5
或'b'
)将为2。这意味着与AND匹配的最大前缀在'b'中结束为2.现在,如果您的最后一个字符与前缀('a'
)的第3个字符匹配,则您的后缀等于前缀。 ("aba"
)
KMP就在那里停了下来。但是你想要所有的比赛。因此,不是以最后一个char结尾的最大匹配('b'
中的2),而是需要找到所有匹配前缀为'b'的前缀。所以你继续进入KMP的内循环,如上所述,检查当前的匹配数量,以'b'结尾(可以为零),如果下一个char等于我们的最后一个char。
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]
。将整个长度视为特殊情况。
(注意我的while
循环和KMP循环之间的相似性。如果你仍然感到困惑,我强烈建议彻底阅读/理解KMP。很容易对此有一个全面的了解,但深刻的理解是真的回答这样的问题很难也很重要。)