用next数组来匹配模拟串的算法

题目描述:输入一个n,表示有n组样例,每个样例有两个字符串,先输入主串,在输入模拟串和位置pos,如果在主串第pos之后能匹配成功就输出yes和模拟串的位置,否则就输出no

#include<stdio.h>
#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");
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值