0x00使用场景
字符串匹配:给定模板串aaa和目标串bbb,求bbb是否为aaa的子串;如果是,返回开始的indexindexindex。
0x01暴力算法
基本思想:如果当前字符匹配成功(S[i]==P[j]S[i] == P[j]S[i]==P[j]),则i++,j++,继续匹配下一个字符;
如果失配(即S[i]!=P[j]S[i]! = P[j]S[i]!=P[j]),i=i−(j−1),j=0i = i - (j - 1),j = 0i=i−(j−1),j=0。相当于每次匹配失败时,i 回溯到匹配序列开始的字符的下一个,j 被置为0,即子串重新开始匹配。
def match(template:str,sub:str)->int:
i=0
j=0
while(i<len(template) and j<len(sub)):
if (template[i]==sub[j]):#match
i+=1
j+=1
else:#Dismatch
i=i-j+1#Backtracking
j=0
if j==len(sub):
return i-j#First index
else:
return None#Failed
0x02 KMP
暴力匹配法是出现错配时回溯到sub串的开头,KMP算法的改进点在于回溯到原串预计算的next值。
简单说:如果出现失配现象,则回退next[current_index]next[{current\_index}]next[current_index]个字符,再从目标串的开头尝试配对。
NEXT的求法
考虑子串的最长相等前后缀和。注意是子串才有。
e.g.:
aba
的最长相等前后缀长度为1,即{a}。注意前缀是ab,后缀是ba,这两个不相等,后缀也是从左到右的。
abcba
仍然是1.
abab
是2,因为有ab=ab。
然后将最长相等前后缀向右移一格,sub[0]的部分补-1再全部+1,就是next
了。
e.g.
s='aabaac'
p=[0,1,0,1,2,0]#最原始的前后缀和数组
p1=[-1,0,1,0,1,2]#右移一格
next=[0,1,2,1,2,3]#全部+1
注意这里加不加1都可以,看选项的一个数字。
NEXT的使用方法
发生失配时:
主串指针不动,子串index回退到j=j-next[j]
(注:j从0开始)