题目来源:(POJ 1961版) 点击打开链接
(HDU 1358版,这两个测试数据不一样)点击打开链接
KMP字符匹配题目,求整个序列中大于1个重复子串位置和数据,利用性质i/(i-next[i])和i%(i-next[i)来判断之,详情可以见这里。这个题POJ的测试数据比较严谨,有些写的不严谨的NEXT数组会被判错。很多人拙计的问为什么错了,下边给个反例,样例和下边的反例过了,你的NEXT函数基本就没有问题了。
举例子:10 abaababaab
正解是:6 2
10 2
错解只有第一个。
//经典Trap:10 abaababaab
// 返回两组 6 2
// 10 2
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int next[1000009];
void get_next(string str) //第一个是-1,以后的直接用j=next[j]就行 ,next[1]开始真的有数
{
int j=0,k=-1;
next[0]=-1;
while(j<str.size())
{
if(k==-1||str[j]==str[k])
{
j++;
k++;
next[j]=k;
}
else
k=next[k];
}
}
int main()
{
int testcase;
int test=1;
while(cin>>testcase && testcase!=0)
{
string tar;
cin>>tar;
get_next(tar);
cout<<"Test case #"<<test<<endl;
for(int i=2;i<=testcase;i++)
{
if(i%(i-next[i])==0 && i/(i-next[i])>1)
{
cout<<i<<" "<<i/(i-next[i])<<endl;
}
}
cout<<endl;
test++;
}
return 0;
}
下边这个NEXT获取函数HDU可以通过,但是无法过上边的反例,有没有犇能告诉我,哪里出问题了。
void build_next(string b)
{
int i,j=0,key=0;
memset(next,0,sizeof(next));
for(i=1;i<b.size();i++)
{
j=next[i-1];
while(j==1 && b[i]!=b[j])
{
j=next[j-1];
}
if(b[j]==b[i])
{
next[i]=j+1;
}
else
next[i]=0;
}
}