码迷,mamicode.com
首页 > 编程语言 > 详细

KMP 算法

时间:2017-10-08 11:13:53      阅读:212      评论:0      收藏:0      [点我收藏+]

标签:技术   out   can   cstring   比较   span   思路   ++   main   

模板

如何在目标串中找到模式串p?

1、暴力枚举起始位置,逐位比较

缺点:枚举太多无用位置,时间复杂度高

Codes:

1 int j;
2 for(int i = 0;s[i];++ i){
3     for(j = 0;p[j];++ j)
4         if(s[i + j] != p[j]) 
5             break;
6     if(!p[j]){ //匹配成功 
7         //Operations
8     }
9 }

复杂度:O((n - m + 1) * m) (n:原串长度,m:匹配串长度)

2、KMP

优点:只枚举了可能有用的位置(其实就是暴力缺点opp. QwQ)

那是如何做到只枚举有用位置的呢?

nxt数组!

①nxt[i + 1] 定义为最大的 j + 1 使得 p[0~j] 是 p[0~i] 的后缀

技术分享

 ②nxt[i] 定义为当 i 位置不匹配时,将跳到 nxt[i] 位置重新匹配(关于nxt数组定义众说纷纭,这里只给出我认为最易懂的定义QwQ)

因为再不匹配时kmp算法并不是再枚举下一位,而是跳到 nxt[i] 继续匹配,所以会明显提高效率,时间复杂度降到线性

例子1:

P   :  0 1 2 3 4 5 6 7

        a b c a b c a d

nxt: -1 0 0 0 1 2 3 4

例子2:

P   :  0 1 2 3 4 5 6 7

        a b a c b a b a

nxt: -1 0 0 1 0 0 1 2

清楚定义之后,计算nxt[]的思路也差不多了

Codes:

 1 void get_nxt(char *p){
 2     int i = 0,j = -1;
 3     nxt[0] = -1; //边界 
 4     while(p[i]){
 5         if(j == -1 || p[j] == p[i]) //到达边界 或 前缀等于后缀 
 6             nxt[++ i] = ++ j; //可以跳到的位置 + 1 
 7         else j = nxt[j]; //不匹配则跳到 nxt[] 
 8     }
 9     return;
10 }

接下来是匹配,可以观察其与暴力的不同或相同点

Codes:

 1 int kmp(char *p,char *s){ //传指针,可以理解为数组
 2     //s:目标串,p:模式串 
 3     int res = 0; //计数,出现次数 
 4     get_nxt(p); //处理nxt 
 5     for(int i = 0,j = 0;s[i];++ i){
 6         while(j != -1 && s[i] != p[j]) 
 7             j = nxt[j]; //若不匹配,跳到 nxt[j] 
 8         ++ j; //匹配上 
 9         if(!p[j]){ //模式串与目标串匹配完成 
10             res ++; //计数 ++ 
11             j = nxt[j]; //若计算重叠串则返回nxt[j] 
12             //Operations 
13         }
14     } 
15     return res;
16 }

模板(其实就是把上面搬过来2333)

Codes:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #define N 1010
 6 
 7 using namespace std;
 8 
 9 char s[N],p[N];
10 int nxt[N];
11 void get_nxt(char *p){
12     int i = 0,j = -1;
13     nxt[0] = -1; //边界 
14     while(p[i]){
15         if(j == -1 || p[j] == p[i]) //到达边界 或 前缀等于后缀 
16             nxt[++ i] = ++ j; //可以跳到的位置 + 1 
17         else j = nxt[j]; //不匹配则跳到 nxt[] 
18     }
19     return;
20 }
21 int kmp(char *p,char *s){ //传指针,可以理解为数组
22     //s:目标串,p:模式串 
23     int res = 0; //计数,出现次数 
24     get_nxt(p); //处理nxt 
25     for(int i = 0,j = 0;s[i];++ i){
26         while(j != -1 && s[i] != p[j]) 
27             j = nxt[j]; //若不匹配,跳到 nxt[j] 
28         ++ j; //匹配上 
29         if(!p[j]){ //模式串与目标串匹配完成 
30             res ++; //计数 ++ 
31             j = nxt[j]; //若计算重叠串则返回nxt[j] 
32             //Operations 
33         }
34     } 
35     return res;
36 }
37 int main(){
38     scanf("%s%s",s,p);
39     cout << kmp(s,p) << \n; 
40     return 0;
41 }

 

KMP 算法

标签:技术   out   can   cstring   比较   span   思路   ++   main   

原文地址:http://www.cnblogs.com/Loizbq/p/7635823.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!