KMP算法不同写法之间区别

网上之所以有这么多版本的KMP算法,是因为有的人写的是最大长度串版本的,有的人写的是next数组版本的(具体区别看下面博文),有的人写的是next优化版的,有的人写的是未优化的,不同人写的循环方法不同,这些写法间的效率是有一定区别的

KMP算法具体讲解看这篇博客,讲的非常非常详细:

https://blog.csdn.net/v_july_v/article/details/7041827#

重点应该在理解Next数组和Next数组的优化

我试着再写一下我理解的优化过程:

比如这张图:

设上面的串为A[],下面的串为B[],下标从0开始

根据最大长度串数组C的定义:

当前子串字符之前的字符串中,有多大长度的相同前缀后缀。例如如果C [j] = k,代表j 之前的字符串中有最大长度为k 的相同前缀后缀。

对于abab这个子串来说,最大长度串数组C就是0 0 1 2,那么next数组(未优化版)就是最大长度值整体向右移动一位,然后初始值赋为-1,即-1 0 0 1。

我们会发现当发生A[3]c与B[3]b失配后,左移两位(3-next[3])后,会A[3]c会再次与B[1]b失配,事实上这是必然发生的,

回看next数组的定义(其实也就是最大长度串数组):j 之前的字符串中有最大长度为k 的相同前缀后缀。既然后缀的这个字符已经失配了,那么前缀相同地方的字符也一定会失配,所以要避免这个情况发生,也就是若:B[j] = B[ next[j] ]就要让B[j] = B[ next[j] ]。

总结一下这个过程:

先求出最大长度串数组,整体左移一位,若B[j] = B[ next[j] ]即B[j] = B[ next[j] ]

最后给出一个nenxt优化版本的代码

 1 int a[1000005];
 2 int b[10005];
 3 int len1, len2;
 4 int Next[10005];
 5 void getNext()
 6 {
 7     int k = -1, j = 0;
 8     Next[0] = -1;
 9     while(j < len2)
10     {
11         if(k == -1 || b[j] == b[k])
12         {
13             k++;
14             j++;
15             if(b[j] != b[k])
16                 Next[j] = k;
17             else//如果这一步失败 那么同值的也会失败
18                 Next[j] = Next[k];
19         }
20         else
21             k = Next[k];
22     }
23 }
24 int kmp()
25 {
26     getNext();
27     int i = 0, j = 0;
28     while(i < len1)
29     {
30         if(j == -1 || a[i] == b[j])
31         {
32             i++;
33             j++;
34         }
35         else
36             j = Next[j];
37         if(j == len2)
38             return i+1-len2;
39         //返回的是匹配到的index,如果是求次数或对错的话需要修改
40     }
41     return -1;
42 }

 

posted @ 2018-08-10 17:21  feifei97  阅读(510)  评论(0编辑  收藏  举报