在用匹配字符串(A)对目标字符串(B)进行匹配的过程中,会出现多次遍历的情况,当A越长,要进行匹配的次数越多,且一旦匹配失效,其时间成本在急剧上升。
在这里,结合其他前辈的经验,理解一下大名鼎鼎的KMP算法的思路吧。
解决思路:
在进行匹配之前,需要计算匹配字符串的部分匹配值。
1.查找目标字符串中第一个与匹配字符串中第一个字符相等的位置,将A移动到该位置,开始匹配;
2.若匹配字符串的第N(N>=2)个字符能匹配目标字符串,则继续匹配,直至,
若(1)在目标字符串中找到匹配字符串,则结束此轮查找;
若(2)在目标字符串中没有查找到匹配字符串,记录当前已成功匹配的数量x和匹配字符串该位置下的部分匹配值t,计算移动位数k=x-t,移动k位,进行下一轮匹配,执行1,2
字符串A:ABCDABD
字符串B:AHADABFABCDABCDABD
有两个概念:已匹配字符数和对应的部分匹配值
已匹配的字符数:在字符串B中,找到已匹配字符串A的数量
对应的部分匹配值:字符串A中,到达某位置时,该部分的字符串的前缀和后缀的公共字符串的长度。
前缀:某字符串除开尾字符外的顺序字符串的集合。
后缀:某字符串除开首字符串的顺序字符串的集合。
以A为例:ABCDABD
到达A时:前缀和后缀都为0,公共字符串长度为0
到达AB时:
前缀:A
后缀:B
公共字符串长度为0
到达ABC时:
前缀:A,AB
后缀:BC,C
公共字符串长度为0
到达ABCD时:
前缀:A,AB,ABC
后缀:D,CD,BCD
公共字符串长度为0
到达ABCDA时:
前缀:A,AB,ABC,ABCD
后缀:A,DA,CDA,BCDA
公共字符串长度为1,为A
到达ABCDAB时:
前缀:A,AB,ABC,ABCD,ABCDA
后缀:B,AB,DAB,CDAB,BCDAB
公共字符串长度为2,为AB
到达ABCDABD时:
前缀:A,AB,ABC,ABCD,ABCDA,ABCDAB
后缀:D,BD,ABD,DABD,CDABD,BCDABD
公共字符串长度为0
还是以开头的字符串为例:
匹配字符串:ABCDABD
目标字符串:AHADABFABCDABCDABD
当开始匹配时:
1.A匹配A,匹配数为1,部分匹配值为0,移动位数为1-0=1,B不与H匹配,往前移动1位,
2.A不与H匹配,往前移动1位,
3.A与A匹配,B与D不匹配,匹配数为1,部分匹配值为0,移动位数为1-0=1,往前移动1位
4.D与A不匹配,往前移动1位,
5.A与A匹配,B与B匹配,F与C不匹配,匹配数为2,部分匹配值为0,往前移动2-0=2位,
6.A与A匹配,B与B匹配,C与C匹配,D与D匹配,A与A匹配,B与B匹配,C与D不匹配,匹配数为6,部分匹配值为2,移动位数为6-2=4位,
- A与A匹配,B与B匹配,C与C匹配,D与D匹配,A与A匹配,B与B匹配,D与D匹配,匹配成功。距离为1+1+1+1+2+4=10
“部分匹配”的实质是,有时候,字符串头部和尾部会有重复。
参考资料:阮一峰的博客。