KMP算法
Posted Grary
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KMP算法相关的知识,希望对你有一定的参考价值。
KMP算法
KMP算法是用于处理字符串匹配问题的,在字符串题目中,会遇到匹配问题,如问s1是否是s的子串?
这时我们就要去扫描这两个字符串,如果使用两层循环暴力枚举这个解的话,就会产生O(n*m)的复杂度,n、m是字符串的长度;
我们用较短的字符串去匹配长的字符串,把他放下面
KMP正是优化了这一过程,如果我们从第一位开始枚举时发现下一个字符互不相等,那么我们就要把下面的字符串右移一位,把上面字符串的第二位去匹配下面字符串的第一位,然后第三位匹配下面的第二位……由于我们从下面的第一位开始搜索,这就产生的大量的重复步骤,我们要简化这一步骤,就产生了KMP这种东西
先来一个前缀包含问题
字符串ABCDABCD
前缀:A 、AB、ABC、ABCD、ABCDA、ABCDAB、ABCDABC
其中ABCDABC中有七个字符,
如果我们把它看成一个字符串,而不仅是一个前缀,我们就发现他的前缀ABC和后缀ABC是一毛一样的,我们就可以根据这个东东处理出一个数组next,next[i]存放的就是这个前i个字符前缀和后缀相同的最大前缀的字符数,这里next[7]=3;
根据这个我们在匹配失败时就可以避免从头再来,直接将next复制给相同字符数就可以,确实很方便,但是不好理解,额,其实也是很好理解的,。
至于next的递推和这个过程基本上是一致的很好理解
#include <iostream> #include <cstring> using namespace std; const int n=1000002; int next[n]; char s1[n], s2[n]; int len1,len2; void getnext() { int j,k; j=0;k=-1;next[0]=-1; while(j<len2) if(k==-1||s2[j]==s2[k]) next[++j]=++k; else k=next[k]; } int address()//返回第一次出现的位置 { int i=0,j=0; getnext(); while(i<len1&&j<len2) { if(j==-1||s1[i]==s2[j]) { i++;j++; } else j=next[j]; } if(j==len2) return i-len2; else return -1; } int count()//返回出现的次数 { int ans=0; int i,j=0; getnext(); for(i=0;i<len1;i++) { while(j>0&&s1[i]!=s2[j]) j=next[j]; if(s1[i]==s2[j]) j++; if(j==len2) { ans++; j=next[j]; } } return ans; } int main() { int sum; int i; cin>>sum; while(sum--) { cin>>s1>>s2; len1=strlen(s1); len2=strlen(s2); cout<<address()<<endl; cout<<count()<<endl; } return 0; }
有同样功能而且好像还更快的是字符hash,但是比起KMP来就知道复杂了不少
以上是关于KMP算法的主要内容,如果未能解决你的问题,请参考以下文章