我自己搭建了博客,以后可能不太在优快云上发博文了,https://www.qingdujun.com/ 。
我在拜读阮一峰老师的这篇文章《字符串匹配的KMP算法》时,最大收获当属手动求部分匹配表的这个例子,(我把它搬过来了,大伙感受一下)——字符串为 P = A B C D A B D P=ABCDABD P=ABCDABD。
字符串 | 前缀 | 后缀 | 部分匹配表 |
---|---|---|---|
A | NULL | NULL | NEXT[0]=0 |
AB | A | B | NEXT[1]=0 |
ABC | A, AB | BC, C | NEXT[2]=0 |
ABCD | A, AB, ABC | BCD, CD, D | NEXT[3]=0 |
ABCDA | A, AB, ABC, ABCD | BCDA, CDA, DA, A | NEXT[4]=1 |
ABCDAB | A, AB, ABC, ABCD, ABCDA | BCDAB, CDAB, DAB, AB, B | NEXT[5]=2 |
ABCDABD | A, AB, ABC, ABCD, ABCDA, ABCDAB | BCDABD, CDABD, DABD, ABD, BD, D | NEXT[6]=0 |
(阮一峰老师的这篇文章,基本上是国内网上讲解KMP算法的开山之作了。其特点简短精悍,又能快速让你明白什么KMP算法、什么是部分匹配表)
此时,你应该可以根据前、后缀的概念,手动求出部分匹配表NEXT[*]
。不妨试试下面这个例子(该例子摘自《算法导论》)——字符串 P = a b a b a c a P=ababaca P=ababaca。
其中,q
表示索引号,string
表示字符串,next[7]
则为字符串对应的部分匹配表。你的结果与上述表格中的一样吗?
问题1:你可能对NEXT[0]=-1? or 0
有所疑惑!
《算法导论》一书上由于下标是从1
开始,所以书中NEXT[*]
存放的内容为前缀的长度(也同样是下标),而计算机程序下标一般是从0
开始,那么长度与下标就相差了一个1
。下文为了与《算法导论》一致,也采用了长度(非下标)的存储方式,也就是说部分匹配表中不会出现-1
类似的字眼(因为前缀长度>=0
)。但这样做是值得的,至少NEXT[*]
与《算法导论》一致,也与考试答案一致。
(我看到网上流传的相关KMP文章,NEXT[*]
各有不同。本文的举例来自于《算法导论》一书,且我无一字更改,所以例子的正确性能得到保证)
1 KMP算法
问题2:OK,部分匹配表NEXT[*]
已经有了。那么,如何利用部分匹配表在必要时快速滑动呢?
举个例子,假设 T = ( . . . b a c b a b a b a a b c a b . . . ) T=(...bacbababaabcab...) T=(...bacbababaabcab...)为一个很长的字符串(以下为截断部分), P = ( a b a b a c a ) P=(ababaca) P=