I - Oulipo -判断子字符串

本文深入讲解KMP算法的实现原理及应用,通过两种C语言实现方式对比,详细介绍了如何求解模式串的最大子字符串长度,并利用KMP算法进行字符串匹配。

I - Oulipo

 
思路:
首先确定好模式串和文本串,对模式串处理,得到nex[]数组,即可确定最大子字符串的长度;
当然我们要清楚,KMP()的作用和原理;
原理即始终遵循nex[i]所在的下标值,表示前i个字符串与后i个字符串相同;
例如:str[9]=" abababc";str[6]='b';
           nex依次对应:nex[1~8]:0 0 1 2 3 4 0
 nex[6]=4:"在ababab"中指前4个字符串:”abab“ 与后四个“abab”相同;
然后就是两个字符串进行比较,注意输入字符串的起始下标和比较时,两者的下标
方法一:C
#include <stdio.h>
#include <string.h>
int nex[10005];
char str1[1000005],str2[10005];
int cnt;
void Get(int len2)
{
    int j=0;
    memset(nex,0,sizeof(nex));//清除
    nex[1]=j;
    for(int i=2;i<=len2;i++)
    {
        while(j&&str2[j+1]!=str2[i])
            j=nex[j];
        if(str2[j+1]==str2[i]) j++;
        nex[i]=j;
    }
}

void kmp(int len1,int len2)
{
    int i=1,j=0;//str1输入的起始坐标是1,注意j=0;难得试出来啦!!
    Get(len2);
    for(i=1;i<=len1;i++)
    {
        while(j&&str1[i]!=str2[j+1]) j=nex[j];
        if(str1[i]==str2[j+1]) j++;
        if(j==len2)//找完一个完整的子字符串时,开始改变j的值!!!!
        {
            cnt++;
            j=nex[j];//千万别忘记
        }
    }
}

int main()
{
    int n;
    int len1,len2;
    scanf("%d",&n);
    getchar();
    while(n--)
    {
        gets(str2+1);
        gets(str1+1);
        len1 = strlen(str1+1);
        len2 = strlen(str2+1);
        cnt = 0;
        kmp(len1,len2);
        printf("%d\n",cnt);
    }
    return 0;
}





方法二:C

#include <stdio.h>
#include <string.h>
int nex[10005];
char str1[1000005],str2[10005];
int cnt;
void Get(int len2)
{
        memset(nex,0,sizeof(nex));//清零!!
        int i = 0,j = -1;
        nex[0] = -1;
        while (i<len2)
        {
            if(j == -1 || str2[i] == str2[j])
            {
                i++,j++;
                if (str2[i]!=str2[j])
                    nex[i] = j;
                else
                    nex[i] = nex[j];
            }
            else
                j=nex[j];
        }
//    for(int i=0;i<=len2;i++)
//        printf("%d ",nex[i]);
//    printf("\n");
}

void kmp(int len1,int len2)
{
        int i=0,j=0;//注意i=0,j=0!!!
        Get(len2);
        while(i<len1)
        {
            if(j==-1||str1[i]==str2[j])
                ++i,++j;
            else
                j=nex[j];
//            printf("j:%d ",j);
            if(j == len2)
            {
                cnt++;
                j = nex[j];
            }
         }
//          printf("\n");
}

int main()
{
    int n;
    int len1,len2;
    scanf("%d",&n);
    getchar();//一定要吃回车!!!
    while(n--)
    {
        gets(str2);
        gets(str1);
        len1 = strlen(str1);
        len2 = strlen(str2);
        cnt = 0;
        kmp(len1,len2);
        printf("%d\n",cnt);
    }
    return 0;
}

多次测试!!结果依然是输入翻了车!!下次一定要记得检测输入!!!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值