lievre

知识补充:

网上看过许多讲解,很多都看得很晕,直到看到一个有讲到字符串的前缀、后缀这个概念后才豁然开朗。

假设字符串 S = “PPAP”,前缀后缀及相关概念如下:

·        前缀:字符串S的前缀,是相对于字符串最后一个字符来说的。除去最后一个字符,包含首字符的所有子串即是字符串S的前缀,这些子串组成的集合即是字符串S的前缀集合。所以 S 的前缀集合 = {“P”,“PP”,“PPA”};

·        后缀:同理,后缀即是相对于字符串的首字符来说的。除去首字符,包含尾字符的所有子串即是字符串S的后缀,这些子串组成的集合就是字符串S的前缀集合。所以 S 的后缀集合就是{“PAP”,“AP”,“P”}

·        PMT:(Partial Match Table,模式匹配表)这是 KMP算法的核心,

PMT中的值是字符串的前缀集合与后缀集合的交集中最长元素的长度,如下图

(来自 <https://blog.csdn.net/x__1998/article/details/79951598>

字符串abababca中,value代表着在该index下,这个子串的前缀集合与后缀集合的交集中,最长元素的长度,(比如index为4时,字符串子串abab的前缀集合与后缀集合的交集,即{“aba”,“a“}中最长元素”aba“的长度3)                                                                                                                                       

 

算法原理:

既然了解了字符串的前缀和后缀,要理解起来就简单多了。如下图:(a、b图摘自:

https://blog.csdn.net/x__1998/article/details/79951598

假设下面的两个字符串,长的为要检索的主字符串,短的为模式字符串,那么从下面可以看到,当i、j移动到(a)图时才发现不匹配,也就是说前面的6个字符是完全匹配的即前面6个字符可以看做一个字符串来看,这样就可以得到前6字符的前缀和后缀集合,在这个例子中,两个集合的交集为{“ab”,“abab”},其中最长元素为“abab”长度为4,那么就保持 i 不动,j移到下标为4的位置(如下b图,相当于把模式字符串向右移动,使相同的前后缀重合)。

·        为啥要这样做呢?相对于朴素的暴力破解匹配模式,KMP不需要 i回溯,j也不需要立刻返回头部,这样节省了大量运算。

·        为啥选最大长度的“abab”而不选择“ab”呢?选择最大长度,就是为了不漏掉可能匹配的子串,如下c图,如果选择了“ab”,那么就错失了匹配上字符串(b图)的良机。

 

 

从上面的模式表及示例图可以看到,其实KMP算法中,真正影响 j 回溯的,并不是第 j位的PMT值而是第 j-1 位的PMT值,如上图,当j = 6时,PMT值为0,但我们却将j回溯到第4位(j = 5的PMT值)。所以为了编程方便,可以将PMT数组向右移一位,并将第一位置为 -1,存入next数组,此处取 -1 也有一定的好处:因为PMT值肯定 >=0,所以设为 -1 也可以作为模式串的头部标志,用来做判断再好不过了。

如下表:(摘自https://blog.csdn.net/x__1998/article/details/79951598

 

代码如下:

 

剖析:

如果按照 a 图来看,则当 i=6,j=6时,只要移动一次模式串(经历一次 j = next[j],即 j = next[6] = 4),就能找到匹配的下标,不太好理解。

所以我这里将主串下标为6的元素 a 改为 b,来辅助理解一下 next数组头元素 置为 -1 在这里的作用,如 d 图。

 

如图,我们按照代码走一遍。

  i.        当 i和 j 都走到 下标6时,c != b,所以 j = next[j] = next[6] = 4;

 ii.        如图e,此时a != b,所以 j = next[j] = next[4] = 2;

iii.        如图f,此时b != a, 所以   j = next[j] = next[2] = 0;

iv.        如图g,此时b != a, 所以 j = next[j] = next[0] = -1;

 v.        如图h,此时b != a, 但是又满足 j = -1,所以 i++,j++,i和 j 都继续往前走了。

在这里可以看到 模式串 首部 置为 -1 的作用了,因为前缀和后缀集合的交集元素长度最小是0, 0 没法判断是不是队头,因为其他位置也有为0的,所以用 -1来判断再好不过了。

 

 

 

 

q 
e 
q

 

 

(h)

 

 

分类:

技术点:

相关文章:

  • 2021-10-25
  • 2021-08-21
  • 2018-12-22
  • 2021-12-30
  • 2021-10-13
  • 2022-01-22
猜你喜欢
  • 2021-08-13
  • 2021-08-02
  • 2021-04-16
  • 2021-10-04
  • 2021-08-27
相关资源
相似解决方案