滑窗:
枚举起点,如果符合尝试扩大窗口
不符合的时候缩小窗口
这样每个起点的最长重复子串都计算了一遍
def longestDupSubstring(self, s):
"""
:type s: str
:rtype: str
"""
n = len(s)
l, r = 0, 1
_max, res = 0, ""
while r <= n:
if s[l:r] in s[l + 1:]:
if r - l > _max:
_max, res = r - l, s[l:r]
r += 1
else:
l += 1
return res
Rabin-Karp 算法
不要每次都去一个字符一个字符地比较子串和模式串,而是维护一个滑动窗口,运用滑动哈希算法一边滑动一边计算窗口中字符串的哈希值,拿这个哈希值去和模式串的哈希值比较,这样就可以避免截取子串,从而把匹配算法降低为 O(N)
这题还用到了二分来快速的查找最长字串的长度应该是多少
def longestDupSubstring(self, s):
"""
:type s: str
:rtype: str
"""
base = 26 #找好一对base和mod,防止碰撞
mod = 10**13+1117
arr = [ord(c)-ord('a') for c in s] #用数组存,方便查找
def check(m,base,mod):
number = 0
l = 0
seen = set()
rem = pow(base, m-1, mod) #注意这里取余,否则计算量超大
for i in range(m-1):
number = (number*base + arr[i])%mod #注意这里取余,否则计算量超大
for i in range(m-1,len(s)):
number = (number*base + arr[i])%mod #注意这里取余,否则计算量超大
if number in seen:
return i
else:
seen.add(number)
number = (number - rem*arr[l])%mod #注意这里取余,否则计算量超大
l += 1
return -1
l,r = 1,len(s)-1
end = -1
while l <= r: #二分查找长度
m = l + (r-l)//2
idx = check(m,base,mod) #返回的是末尾下标
if idx != -1:
l = m + 1
length = m
end = idx
else:
r = m - 1
return s[end-length+1:end+1] if end != -1 else "" #注意这里判断end