您的位置:首页 > 其它

烦躁KMP

2015-11-03 21:59 141 查看
//这代码是我网上抄来的,我大概讲解一下算法精髓好了
//题目在这
//(本人写的kmp卡了四十秒才卡出正确答案)
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

//我们的目的是为了在a字符串中寻找b出现的次数
char a[1000100],b[10010];

//la为a的长度,lb为b的长度,cnt为出现的次数(cnt每次都要更新)
int la,lb,f[10010],cnt;

//麻烦从主函数看起,这是好习惯

//下面就是kmp算法的匹配值函数了(大概就是你们在各大博客看到的Next数组)
void k_mp()
{
//以下尤为重要,建议大家一个字一个字看过去
/*这个函数是用来算出f数组,也就是匹配值数组,
而匹配值数组经过我的研究是这样子的:在第i位
寻找1至i中后缀和前缀相等的位数,接下来讲讲什
么是后缀以及前缀:

先输入b:a  b  b  a  b  b  d  e  a
匹配值f: 0  0  0  1  2  3  0  0  1

前三个先不说,
看第四个f值为1,为什么为1,因为从1到4之间的字符,开头只有1个与最后1个相等,即a=a;
而第五个为什么为2,因为1到5之间,前面2个与后面2个相同,即ab=ab;
那么第六个为3就是因为1到6的字符中,前三个字符和后三个字符相等,即abb=abb;
第七个为0是因为1至7之间没有开头和结尾相同的字符,
这样应该就会懂得f数组怎么来了吧

而f数组的作用就是,当找到一个不匹配的字符,例如
在i=5的地方(b字符的位置)不匹配的时候,我们不必
回溯到0开始,只需从f[i-1]的地方(f[4]=1)接着匹
配即可这样j也不用回溯了,就节省了大把的时间;
*/

//此处先更新cnt=0;
cnt=0;

//len是用来有几位相等的字符
int len=0,i=1;

//开头第一个应该定义为0(说实话,我也不知道为什么)
f[0] = 0;
while(i<lb)
{

//len是用来记录前面已经有多少个字符相等了
if(b[i]==b[len])
{

//如果又相等了一个,len++
len++;

//然后f[i]=len;i++,计算下一个
f[i]=len;
i++;
}

//下面这一段我自己也不是很懂
else
{
if(len!=0)
len=f[len-1];
else
{
f[i] = 0;
i++;
}
}
}

/*
这个留给你们看f数组好了

for(int i=0;i<lb;i++)
cout<<f[i]<<' ';
cout<<endl;

*/
}
void KMP()
{

//la,lb算出来以后,就去做匹配值工作了
la=strlen(a);
lb=strlen(b);

//匹配值计算开始(这是最虐心的部分)
k_mp();

int i=0,j=0;
while(i<la)
{

//如果相等的话就两个都加1
if(b[j]==a[i])
{
j++;
i++;
}

//当j==lb说明b串匹配到了
if(j==lb)
{

//就记录下来一个
cnt++;

//可以用printf("第%d个匹配的位置在:%d\n",cnt,i-j+1)知道从哪里开始匹配的
//如果要继续查找,那么f数组就派上用场了
j=f[j-1];
}
else if(b[j]!=a[i])
{
//每次有不匹配的时候,就追溯到f[j-1]的位置
if(j!=0)
j=f[j-1];

//当然如果j=0就不用了,直接匹配下一位就行,即i++
else
i++;
}
}

//这样这一题就搞定了,希望你们能看得懂此题解
}

//咱们先看主函数
int main()
{
int n;

//输入要输入的组数n,表示有n组数据
scanf("%d",&n);
while(n--)
{
//先输入b,再输入a
scanf("%s%s",b,a);

//然后用Kmp算法算出b在a中出现的次数
KMP();

//输出答案
printf("%d\n",cnt);
}
return 0;
}


 

kmp算法,我这弱渣看了一星期

为什么好用,就是因为时间复杂度够低

达到(m+n)

它并不是一个一个 匹配过去的

而是跳着判断这些字符是否相等的

若有不足

望大神指点,,,,

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: