两种KMP题+KMP模版整理

那年仲夏 提交于 2020-03-04 04:35:27

最近稍微看了下KMP,不是很懂他们大神的A题姿势,但是模版总该还是要去学的。

其中next数组的求法有两处区别。

第一种:求主串中模式串的个数。HDU2087 剪花布条和HDU4847 Wow! Such Doge!。这两道都比较水可以暴力string::find函数过,

第一个代码:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
int nextval[101010];
void getnext(char s[],int next[])
{
    int j=0,k=next[0]=-1;
    int len=strlen(s);
    while (j<len-1)  //
    {
        if(k==-1||s[k]==s[j])
        {
            j++;
            k++;
            next[j]=next[k];  //
        }
        else
            k=next[k];
    }
}
int sea(char s[],char t[])
{
    int cnt=0;
    int i=0,j=0;
    int la=strlen(s),lb=strlen(t);
    while (i<la&&j<lb)
    {
        if(j==-1||s[i]==t[j])
        {
            i++;
            j++;
        }
        else
            j=nextval[j];
        if(j==lb)
        {
            cnt++;
            j=nextval[j];            
        }    
    }
    return cnt;
}
int main(void)
{
    char a[1010]={0},b[1010]={0};
    while (cin>>a)
    {
        if(strcmp(a,"#")==0)
        {
            break;
        }
        cin>>b;
        memset(nextval,0,sizeof(nextval));        
        getnext(b,nextval);
        cout<<sea(a,b)<<endl;
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
    }
    return 0;
}

后一题代码:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
int nextval[101010];
void getnext(char s[],int nextval[])
{
    int j=0,k=-1;
    nextval[0]=-1;
    int lenp=strlen(s);
    while(j<lenp-1)    //
    {
        if(k==-1||s[j]==s[k])
        {
            k++;
            j++;
            nextval[j]=nextval[k];//
        }            
        else
            k=nextval[k];
    }
}
int sea(char s[],char t[])
{
    int cnt=0;
    int i=0,j=0;
    int la=strlen(s),lb=strlen(t);
    while (i<la&&j<lb)
    {
        if(j==-1||s[i]==t[j])
        {
            i++;
            j++;
        }
        else
            j=nextval[j];
        if(j==lb)
        {
            cnt++;
            j=nextval[j];            
        }    
    }
    return cnt;
}
void change(char a[])
{
    int len=strlen(a);
    for (int i=0; i<len; i++)
    {
        a[i]=tolower(a[i]);
    }
}
int main(void)
{
    char a[1000010]={0},b[]="doge";
    getnext("doge",nextval);
    int cntt=0;
    while (gets(a)!=NULL)
    {    
        change(a);        
        cntt+=sea(a,b);
        memset(a,0,sizeof(a));
    }
    printf("%d\n",cntt);
    return 0;
}

第二种:求子串出现个数,比如abababa    aba  要是按第一种求法,这个答案会是2,但出现次数不是个数,因此答案是3。例题为POJ 3461

代码:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
int nextval[101010];
void getnext(char s[],int nextval[])
{
	int j=0,k=-1;
	nextval[0]=-1;
	int lenp=strlen(s);
	while(j!=lenp)  //
	{
		if(k==-1||s[j]==s[k])
			nextval[++j]=++k;  //
		else
			k=nextval[k];
	}
}
int sea(char s[],char t[])
{
	int cnt=0;
	int i=0,j=0;
	int la=strlen(s),lb=strlen(t);
	while (i<la&&j<lb)
	{
		if(j==-1||s[i]==t[j])
		{
			i++;
			j++;
		}
		else
			j=nextval[j];
		if(j==lb)
		{
			cnt++;
			j=nextval[j];			
		}	
	}
	return cnt;
}
int main(void)
{
	char a[1000010]={0},b[1000010]={0};
	int tcase;
	scanf("%d",&tcase);
	while (tcase--)
	{	
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(nextval,0,sizeof(nextval));
			
		scanf("%s%s",b,a);					
		getnext(b,nextval);
		printf("%d\n",sea(a,b));				
	}
	return 0;
}

至于为什么可以这么玩,让我补完作业再慢慢研究

  
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!