KMP
来源:互联网 发布:算法复杂性影响因素 编辑:程序博客网 时间:2024/06/07 22:36
KMP算法
在介绍KMP算法之前,先介绍一下BF算法。
一.BF算法
BF算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串P的第一个字符进行匹配,若相等,则继续比较S的第二个字符和P的第二个字符;若不相等,则比较S的第二个字符和P的第一个字符,依次比较下去,直到得出最后的匹配结果。
举例说明:
S: ababcababa
P: ababa
BF算法匹配的步骤如下
i=0 i=1 i=2 i=3 i=4
第一趟:ababcababa 第二趟:ababcababa 第三趟:ababcababa 第四趟:ababcababa 第五趟:ababcababa
ababa ababa ababa ababa ababa
j=0 j=1 j=2 j=3 j=4(i和j回溯)
i=1 i=2 i=3 i=4 i=3
第六趟:ababcababa 第七趟:ababcababa 第八趟:ababcababa 第九趟:ababcababa 第十趟:ababcababa
ababa ababa ababa ababa ababa
j=0 j=0 j=1 j=2(i和j回溯) j=0
i=4 i=5 i=6 i=7 i=8
第十一趟:ababcababa 第十二趟:ababcababa 第十三趟:ababcababa 第十四趟:ababcababa 第十五趟:ababcababa
ababa ababa ababa ababa ababa
j=0 j=0 j=1 j=2 j=3
i=9
第十六趟:ababcababa
ababa
j=4(匹配成功)
代码实现:
int BFMatch(char *s,char *p){ int i,j; i=0; while(i<strlen(s)) { j=0; while(s[i]==p[j]&&j<strlen(p)) { i++; j++; } if(j==strlen(p)) return i-strlen(p); i=i-j+1; //指针i回溯 } return -1; }
二.KMP算法
KMP算法之所以叫做KMP算法是因为这个算法是由三个人共同提出来的,就取三个人名字的首字母作为该算法的名字。其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除了指针i的回溯问题,只需确定下次匹配j的位置即可,使得问题的复杂度由O(mn)下降到O(m+n)。
在KMP算法中,为了确定在匹配不成功时,下次匹配时j的位置,引入了next[]数组,next[j]的值表示P[0...j-1]中最长后缀的长度等于相同字符序列的前缀。
对于next[]数组的定义如下:
1) next[j] = -1 j = 0
2) next[j] = max(k): 0<k<j P[0...k-1]=P[j-k,j-1]
3) next[j] = 0 其他
如:
P a b a b a
j 0 1 2 3 4
next -1 0 0 1 2
即next[j]=k>0时,表示P[0...k-1]=P[j-k,j-1]
因此KMP算法的思想就是:在匹配过程称,若发生不匹配的情况,如果next[j]>=0,则目标串的指针i不变,将模式串的指针j移动到next[j]的位置继续进行匹配;若next[j]=-1,则将i右移1位,并将j置0,继续进行比较。
代码实现如下:
int KMPMatch(char *s,char *p){ int next[100]; int i,j; i=0; j=0; getNext(p,next); while(i<strlen(s)) { if(j==-1||s[i]==p[j]) { i++; j++; } else { j=next[j]; //消除了指针i的回溯 } if(j==strlen(p)) return i-strlen(p); } return -1;}
因此KMP算法的关键在于求算next[]数组的值,即求算模式串每个位置处的最长后缀与前缀相同的长度, 而求算next[]数组的值有两种思路,第一种思路是用递推的思想去求算,还有一种就是直接去求解。
1.按照递推的思想:
根据定义next[0]=-1,假设next[j]=k, 即P[0...k-1]==P[j-k,j-1]
1)若P[j]==P[k],则有P[0..k]==P[j-k,j],很显然,next[j+1]=next[j]+1=k+1;
2)若P[j]!=P[k],则可以把其看做模式匹配的问题,即匹配失败的时候,k值如何移动,显然k=next[k]。
因此可以这样去实现:
void getNext(char *p,int *next){ int j,k; next[0]=-1; j=0; k=-1; while(j<strlen(p)-1) { if(k==-1||p[j]==p[k]) //匹配的情况下,p[j]==p[k] { j++; k++; next[j]=k; } else //p[j]!=p[k] k=next[k]; }}
题目大意:
给你两个字符串p和s,求出p在s中出现的次数。
#include<iostream>#include<cstring>#include<cstdio>#include<string>#include<algorithm>using namespace std;#define N 100010char s[N * 10], p[N];int nextval[N];int lens, lenp;void getnext(){int i = 0, j = -1;nextval[0] = -1;while(i != lenp){if(j == -1 || s[i] == s[j])nextval[++i] = ++j;elsej = nextval[j];}}int KMP(){int i = 0, j = 0, count = 0;while(i != lens && j != lenp){if(s[i] == p[j] || j == -1)++i, ++j;elsej = nextval[j];if(j == lenp){//return i-lenp; count++;j = nextval[j];}}return count;}int main(){int ncase;int len;int ans;scanf("%d", &ncase);while(ncase--){scanf("%s%s", p, s);lens = strlen(s);lenp = strlen(p);getnext();ans = KMP();printf("%d\n", ans);}return 0;}
- KMP
- KMP
- KMP
- KMP
- KMP
- KMP
- kmp
- kmp
- KMP
- kmp
- KMP
- KMP
- KMP
- kmp
- KMP
- KMP
- kmp
- KMP
- sizeof计算二维数组长度的问题
- bzoj 1726: [Usaco2006 Nov]Roadblocks第二短路
- B树索引
- [题目] Section 1.2 Milking Cows(USACO)
- 是什么影响了你的速度?802.11g
- KMP
- bzoj 1029: [JSOI2007]建筑抢修
- java 字节流与字符流的区别
- JavaScript语言核心(一)——类型、变量和值
- Ubuntu 下安装hadoop
- TCP/IP详解--TIME_WAIT状态存在的原因
- [题目] Section 1.2 Palindromic Squares
- ceshiyixia
- Android ActionBar完全解析,使用官方推荐的最佳导航栏(上)