05.KMP算法之深度解析(二)

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的过程为一个递归的过程
发布了58 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Miracle_520/article/details/101124646