一、KMP算法
T:"baaccabaaccabc"
P:"aacca"
第一步,先维护好最长公共前缀表。
a 0 (前后字符相等的个数)
aa 1
aac 0
aacc 0
aacca 1
最前面补个-1,最终得到 a a c c a
-1 0 1 0 0 1 #应用时,对应1~5
代码实现:
def getpnext(self, sub):
#双指针法,建立出pnext表
p, n = 0, len(sub)
pnext = [0]*n #对应
i = 1 #单字符默认为0,不用再比较
while i<n:
if sub[i] == sub[p]:
pnext[i] = p+1 #记录值
p += 1 #递增继续比较下一个
i += 1
elif p != 0: #值不相等,但是之前有相等的,p需要从头开始比较起
p = pnext[p-1]
else: #值不等且p回到头部时,重新比较时,i到下一位
pnext[i] = 0
i += 1
return pnext
代入 "aacca"时,返回pnext=[0, 1, 0, 0, 1]
第二步,遍历表,根据pnext进行移动匹配。
def kmp(self, s, sub):
n = len(s)
m = len(sub)
pnext = self.getpnext(sub) #拿到最长公共前后缀表
ret = []
i, j = 0, 0 #同时遍历2个字符串
while i<n: #遍历主串为主,主串中可能存在多个子串
if s[i] == sub[j]:
i += 1
j += 1
elif j != 0: #子串存在部分匹配的情况时,借助pnext跳过逐个比较
j = pnext[j-1] #对应j-1
else:
i += 1 #不存在部分匹配,i直接下一位
#考虑子串已匹配到的情况,主串还存在多个子串。
if j == m: #子串匹配到
ret.append(i-j) #记录匹配子串的起始位置
j = 0 #子串重新开始,主串i上面步骤已经移位
#优化步骤:剩余主串长度,已不够剩余子串匹配时,直接退出。
if n-i-1 < m-j-1:
break
return ret
输入: "baaabcaabc", "aabc"
输出: [2, 6]
二、字符串匹配问题
s:"abcbcdedefg"
sub: "bcde"
将s串中含有sub串的部分剔除。
注意:剔除一次后,s:"abcdefg" 扔有sub串,继续剔除
1、暴力匹配的方法,利用库函数:
def DelDupStr(self, s, sub):
if not s or not sub:
return
n = len(sub)
while sub in s:
if sub in s:
index = s.index(sub)
s = s[:index] + s[index+n:]
else:
break
return s, sub
2、KMP算法匹配,简化时间复杂度