题目描述:输入一个n,表示有n组样例,每个样例有两个字符串,先输入主串,在输入模拟串和位置pos,如果在主串第pos之后能匹配成功就输出yes和模拟串的位置,否则就输出no
#include<string.h>
int next[1000];
void makenext(char ch[], int m)//next数组的作用是:当第j个字符匹配失败是,将主串中的第i个(原本和j匹配)和next[j]匹配,当然next数组的建立过程已经体现了最大程度的减小时间复杂度
{
int i=1,j=2;
next[i]=0;
for(j=2;j<=m;j++){
i=j-1;//i=j是错的
while(next[i]!=0&&ch[next[i]-1]!=ch[j-2]){
i=next[i];
}
if(next[i]==0){
next[j]=1;
}
else {
next[j]=next[i]+1;
}
}
int nextval[1000];
nextval[1]=0;
for(j=2;j<=m;j++){
int i=j;
while(next[i]!=0&&ch[next[i]-1]==ch[j-1]){
i=next[i];
}
if(next[i]==0){
nextval[j]=0;
}
else{
nextval[j]=next[i];
}
}
}
int main()
{
int num;
int n,m,i,j;
scanf("%d",&num);
getchar();
int pos;
char th[1000],ch[1000];
while(num--){
gets(th);
gets(ch);
scanf("%d",&pos);
getchar();
n=strlen(th);//主串
m=strlen(ch);
makenext(ch,m);
i=pos;
j=0;
while(i<n&&j<m){
if(th[i]==ch[j]||j==-1){
i++;
j++;
}
else {
j=next[j+1]-1;//j表示的是序号
}
}
if(j==m){
printf("YES %d\n",i-j+1);
}
else printf("NO\n");
}
return 0;
}
题解:
关键是next数组的建立和模拟串的移动
代码如下
1.next数组的建立:(含有改进的nextval[]数组)
void makenext(char ch[])
{
int i=1,j;
int next[i]=0;
for(j=2;j<=m;j++){//j代表的是模拟串中第j个字符,m是模拟串ch[]中字符的个数
i=j-1;
while(next[i]!=0&&ch[next[i]-1]!=ch[j-2]){
i=next[i];
}
if(next[i]==0){
next[j]=1;
}
else {
next[j]=next[i]+1;
}
}
int nextval[1000];
nextval[1]=0;
for(j=2;j<=m;j++){
int i=j;
while(next[i]!=0&&ch[next[i]-1]==ch[j-1]){
i=next[i];
}
if(next[i]==0){
nextval[j]=0;
}
else{
nextval[j]=next[i];
}
}
for(i=1;i<=m;i++){
printf("%d ",nextval[i]);
}}
2:模拟串的移动:
int i=0;j=0;//m代表模拟串的字符数,n代表主串的字符数
while(i<n&&j<m){
if(th[i]==ch[j] || j==-1){
i++;
j++;
}
else {
j=next[j+1]-1;
}
}
if(j==m){
printf("YES %d\n",i-j+1);
}
else {
printf("NO\n");
}