KMP算法

//先上程序,关键是理解思想。
#include <iostream>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
 using namespace std;
 char p[1000], s[1000];
 int next[1000];
 void getnext() {
   int i = 0, j = -1, len = strlen(p);
   next[0] = -1;
   while (i < len - 1) {
     if (j == -1 || p[j] == p[i]) {
       j++; i++; next[i] = j;
     }
     else j = next[j];
   }
 }
 int kmp() {
   int i = -1, j = -1, lenp = strlen(p), lens = strlen(s);
   getnext();
   while (j != lenp && i < lens) {
     if (j == -1 || s[i] == p[j]) {++i; ++j;}
     else j = next[j];
   }
   if (j == lenp) return i - j;
   else return -1;
 }
 int main(void) {
 #ifndef ONLINE_JUDGE
   freopen("kmp.in", "r", stdin);
 #endif
   int n;
   while (~scanf("%d", &n)) 
   while (n--){
     scanf("%s%s", p, s);
     if (kmp() == -1) {
       printf("No\n");
     } else printf("%d\n", kmp());
   }
 
   return 0;
 }

 上面是测试程序,输出字符串,模式串,然后输出模式串的位置,如果不存在,则输出-1;

 基本思想就是:

一个s字符数组,和一个模式串p字符数组,用两个标志i, j分别记录两个字符串正在匹配的位置,

用一个next数组,记录当失配时,标志j应该回退的位置,注意:这里,标志i不需要回退,

这正是和暴力算法的区别,也就是说,只需要根据模式串的特点,在失陪的时候回退标志j所指的位置。

而不需要回退标志i所指的位置。

所以,关键就是怎么计算next数组。

 

 注意,构造next数组的时候,让next[0] = -1;k的作用就是,记录在这个位置之前,(不算这个位置)满足这段字符串的后缀和前缀对应字母相同的后缀或前缀的长度最大值,比如:

 

模式串是  a   b   a   b   a

next数组  -1  0  0   1   2

数组下标   0   1  2   3   4

 

 

当下表是4的字母a失配的时候,比如s字符串是a b a b c,也就是说,模式串的第三个a和s字符串中的c失配的时候,此时,j是4,这个时候,j该回退到哪里呢?当然不能是0,因为,如果回退到0就会出现多余的情况,所以按照KMP思想,回退到2即可,这个时候,模式串中第二个a和s字符串中的c开始比较,后面情况一样。

 

基本思想就是这样……

你可能感兴趣的:(Algorithm)