KMP题目

6 篇文章 0 订阅
1 篇文章 0 订阅

KMP题目(三道HDU题目)

HDU _1711原题
题目大意: 给出两个数字序列:a [1],a [2],…,a [N]和b [1],b [2],…,b [M] (1 <= M <= 10000,1 <= N <= 1000000)。你的任务是找到一个数字K,它使[K] = b [1],[K + 1] = b [2],…,a [K + M - 1] = b [ M]。如果存在多个K,则输出最小的K.
解题思路:这道题就是比较经典,简单的KMP算法题,只要掌握KMP即可写出
代码实现:

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int N1=1e6+5;
int a[N1],b[10000+5];
int Next[N1];
int N,M;
void getnext()
{
	int i,j;
	Next[0]=-1;
	i=0;
	j=-1;
	while(i<M)
	{
		if(b[i]==b[j]||j==-1)
		{
			i++;
			j++;
			Next[i]=j;
		}
		else
		j=Next[j];
	}
}

/*
char a[i] 主串 
char b[j] 子串 
*/
int kmp()//返回下标 子符串 与 主符串 匹配的下标
{
	int i,j;
	i=0,j=0;
	getnext();
	while(i<N)
	{
//		if(j==M-1&&a[i]==b[j])
//		return i-j+1;
		if(a[i]==b[j]||j==-1)
		{
			i++;
			j++;	
		}
		else
		j=Next[j];
		if(j==M)
		return i-j+1;
	 } 
	 return -1;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&N,&M);
        for(int i=0;i<N;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<M;i++)
            scanf("%d",&b[i]);
	    printf("%d\n",kmp());
    }
    return 0;
}
//int main()
//{//超时 
///*
//超时解决方法 
//用cin输入会超时,但加入下面三行便不会了 
//ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
//*/
//
//	int T;
//	
//	cin>>T;
//	while(T--)
//	{
//		cin>>N>>M;
//		for(int i=0;i<N;i++)
//		cin>>a[i];//主串 
//		for(int i=0;i<M;i++)
//		cin>>b[i];//子串
//		cout<<kmp()<<endl;		
//	 } 
//
//	return 0;
// } 

HDU_1358原题链接
题目大意: 求字符串的前缀是否为周期串,若是,打印循环节的长度及循环次数,l连续打印到最后;
题解思路: 先构造出 next[] 数组,下标为 i,定义一个变量 j = i - next[i] 就是next数组下标和下标对应值的差,如果这个差能整除下标 i,即 i%j==0 ,则说明下标i之前的字符串(周期性字符串长度为 i)一定可以由一个前缀周期性的表示出来,这个前缀的长度为刚才求得的那个差,即 j,则这个前缀出现的次数为 i/j 。所以最后输出i和i/j即可。
代码实现:

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int N=1e6+5;
char a[N];
int Next[N];
int len;
void getnext()
{
	int i,j;
	i=0,j=-1;
	Next[0]=-1;
	while(i<=len)
	{
		if(j==-1||a[i]==a[j])
		Next[++i]=++j;
		else
		j=Next[j];
	}
}
int kmp()
{
	
	
}
int main()
{
	int t;
	int m=1;
	while(scanf("%d",&t)&&t)
	{
		scanf("%s",a);
	    len=t;
	    getnext();
	    
	   	printf("Test case #%d\n",m++);
	    for(int i=2;i<=t;i++)
	    {
	    	if(Next[i]==0)
	    	continue;
	    	int j=i-Next[i];
	    	if(i%j==0)
	    	printf("%d %d\n",i,i/j);
		}
		cout<<endl;
	    //cout<<Next[i]<<endl;
    }
	
	return 0;
 } 

HDU_2087原题链接
题目大意: 匹配字符串,匹配出多少,输出多少
解题思路: 基础KMP
代码实现:

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;

int Next[1005];
char str[1005];
char a[1005];
int len,len_str;
void getnext()
{
	int i,j;
	i=0;
	j=-1;
	Next[0]=-1;
	while(i<=len)
	{
		if(a[i]==a[j]||j==-1)
		Next[++i]=++j;
		else
		j=Next[j];
	}
}
int KMP()
{
	int p=0;
	int i=0,j=0;
	getnext();
	while(i<len_str)
	{
		if(a[j]==str[i]||j==-1)
		{
			i++;
			j++;
//			cout<<i<<"---"<<j <<"  "<<Next[i]<<endl;
		}
		else
		{
			j=Next[j];
//				cout<<i<<"---"<<j <<"  "<<Next[i]<<endl;
		}
		if(j==len)
		{
			p++;
			j=0;
		}
	}
	return p;
}
int main()
{
	while(scanf("%s",str))
	{
		if(str[0]=='#'&&strlen(str)==1)
		return 0; 
		scanf("%s",a);
		len=strlen(a);
		len_str=strlen(str);
//		getnext();
//		for(int i=0;i<=)
		printf("%d\n",KMP());
	}
	
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值