FZU - 1901(kmp求所有的循环节+注意getnext()摸板的不同性)

FZU - 1901

题意:输出所有可能的循环节。
思路:对next数组的理解。
反思:一开始的想法是找出最小循环节len-next[len].然后用最小循环节来找所有可能的循环节。后来一直wa。用随机法打了一些表找到了一组能证明错误的数据ababaaaabab.用最小循环节来求答案是7,11,正确答案是7,9,11。最小循环节不能代表所有循环节。
一开始我的代码在找所有的循环节的时候,一旦当我遇到匹配不上的时候就会退出循环不再找了,其实还可以将未匹配的位置向左移动一位就又可以了,我原来的错误代码就因为如此漏了好多种情况
AC代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1000005;
char s[maxn];
int nxt[maxn];//abcabcabc
void getnext(int len)
{
	int i=1,j=0;
	nxt[1]=0;
	while(i<=len){
		if(j==0||s[i]==s[j]){
			i++;
			j++;
			nxt[i]=j;
		}
		else{
			j=nxt[j];
		}
	}
}
int main()
{
    int t;
	scanf("%d",&t);
	int C=1;
	queue<int> q;
	while(t--){
		scanf("%s",s+1);
		int len=strlen(s+1);
		getnext(len);
        int p;
		while(!q.empty()){
			q.pop();
		}
	    int pre=len;
		while(nxt[pre]>1){
		   if(s[pre]==s[nxt[pre]]){
		   	q.push(len-nxt[pre]);
		   	pre=nxt[pre];
		   }
		   else{
		   	q.push(len-nxt[pre]+1);
		   	pre=nxt[pre]-1;
		   }
		} 
		if(nxt[pre]>0&&s[pre]==s[nxt[pre]]){
			q.push(len-nxt[pre]);
		}
		q.push(len);
		printf("Case #%d: %d\n",C++,q.size());
		while(!q.empty()){
			int ko=q.front();
			if(q.size()==1)
			printf("%d\n",ko);
			else{
				printf("%d ",ko);
			}
			q.pop();
		}
	}
	return 0;
}
错误代码:

```cpp
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1000005;
char s[maxn];
int nxt[maxn];//abcabcabc
void getnext(int len)
{
	int i=1,j=0;
	nxt[1]=0;
	while(i<=len){
		if(j==0||s[i]==s[j]){
			i++;
			j++;
			nxt[i]=j;
		}
		else{
			j=nxt[j];
		}
	}
}
int main()
{
    int t;
	scanf("%d",&t);
	int C=1;
	queue<int> q;
	while(t--){
		scanf("%s",s+1);
		int len=strlen(s+1);
		getnext(len);
        int p;
		if(s[len]==s[nxt[len]]){
			p=len-nxt[len];
		} 
		else{
			p=len;
		}
		while(!q.empty()){
			q.pop();
		}
	    int pre=len;
		while(nxt[pre]>0){
			if(s[pre]==s[nxt[pre]]){
				q.push(len-nxt[pre]);
				pre=nxt[pre]; 
			}
			else{
				break;//这一步是错的,当匹配不上时要向左移动一位,而不是跳出循环,原因都是nxt[]初始值不一样,为了避免麻烦,我们还可以将nxt[0]设为-1,也就是字符串下标从0开始,终于感受到求next[]时字符串下标从0开始的好处!!!
			}
		} 
		q.push(len);
		printf("Case #%d: %d\n",C++,q.size());
		while(!q.empty()){
			int ko=q.front();
			q.pop();
			printf("%d ",ko);
		}
		printf("\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值