0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
---|---|---|---|---|---|---|---|---|---|---|---|
S: | a | b | c | a | b | a | b | c | a | b | x |
P: | a | b | c | a | b | x | |||||
多余 | a | b | c | a | b | x | |||||
多余 | a | b | c | a | b | x | |||||
a | b | c | a | b | x | ||||||
a | b | c | a | b | x | ||||||
匹配 | a | b | c | a | b | x | |||||
KMP算法: | |||||||||||
a | b | c | a | b | x | ||||||
匹配: | a | b | c | a | b | x |
- 因为第一次匹配时,在S[5] != P[5](a != x)处失配,按照暴力匹配算法,此时应判断S[1] 与P[0]是否相等,发现不相等,则继续判断S[2]与P[0],发现不相等,则继续判断S[3]与P[0],发现相等,判断S[4]与P[1]是否相等。其实以上4步完全是多余的
- 多余的原因:在第一次匹配时,我们已经知道S[0]-S[4]与模式串P的部分匹配关系(P[0]-P[4])即:S[5]之前的都已经知道和模式串P的匹配关系了,不需要重写回溯S来判断了,因为abcab的最大前后缀匹配个数为2,即:S的后缀:S[3]-S[4]与P的前缀P[0]-P[1]是匹配的,则只需要从P[2]与S[5]开始判断即可(如果字符串不存在前后缀匹配,则从P[0]开始匹配,例如ab的最大前后缀匹配个数为0,则判断S[5]与P[0]是否相等,相等,则i++,j++继续向后匹配
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
---|---|---|---|---|---|---|---|---|---|---|---|
S: | a | a | a | a | b | c | d | e | f | ||
P: | a | a | a | a | a | x | |||||
多余 | a | a | a | a | a | x | |||||
多余 | a | a | a | a | a | x | |||||
多余 | a | a | a | a | a | x | |||||
多余 | a | a | a | a | a | x | |||||
a | a | a | a | a | x | ||||||
KMP改进: | |||||||||||
a | a | a | a | a | x | ||||||
a | a | a | a | a | x |
- 第一次匹配,S[4] !=P[4],此时应用KMP算法,应将S[4]与P[3]比较,但是因为P[3]=P[4],所以S[4]与P[3]的比较是多余的,我们已经知道他们的大小关系。同理,P[2]、P[1]、P[0]与S[4]的比较都是多余的。
- next值的含义:找到模式串中的一个位置k,使得P[k]的值与刚才失配的S值比对,以此省略大多数没有用的步骤。但是我们不希望找到的这个P[k]的值和P[j]的值相等,因为我们知道P[j]与失配处的S的关系。
- 所以,当P[j] == P[next[j]]时,我们应该找P[next[j]]的下一个next值对应的P值来与刚才失配的S进行匹配。
KMP算法的核心:通过利用已经匹配了的P的信息,来尽可能的减少没有必要的步骤,通过P的信息可以知道下面有多少步骤是可以直接省略的,也就是知道,下面有多少步骤的匹配关系是已知的。
一个字符串,前缀、后缀相等的个数的意义是什么?
abcabx
- 最大前缀、后缀匹配个数:2(与字符串的最后两位才有可能匹配)
- 存在的前缀、后缀匹配个数:2
a | b | c | a | b | x失配的地方 | ||||
---|---|---|---|---|---|---|---|---|---|
一定不匹配 | a | b | c | a | b | y | |||
一定不匹配 | a | b | c | a | b | y | |||
可能匹配(y!=c,所以c匹不匹配不知道) | a | b | c | a | b | y |
aaaaax
- 最大前缀、后缀匹配个数:4(与字符串的最后4位才有可能匹配)
- 存在的前缀、后缀匹配个数:1、2、3、4
- 从匹配个数最多的开始找,顺序为:4、3、2、1
a | a | a | a | a | x | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
可能匹配(a!=y,所以匹不匹配不知道) | a | a | a | a | a | y | ||||||
一定不匹配(已知a不匹配了,而下一个next值对应的又是a,显然不匹配) | a | a | a | a | a | y | ||||||
一定不匹配 | a | a | a | a | a | y | ||||||
一定不匹配 | a | a | a | a | a | y | ||||||
一定不匹配 | a | a | a | a | a | y | ||||||
改进的KMP:直接跳到next为-1 | a | a | a | a | a | y |
- 因为P[j]的next对应的值等于P[j],而我们的目的是匹配我们不知道的P。所以我们要继续寻找下一个next值,直到找到不等于P[j]为止,或者找到的P为P[0]为止。(此处找next的过程为一个递归的过程)