【HDU 2087】【KMP】

一道kmp模板题,发现我还是有一些细节没有理解到位

先简述一下kmp算法:给定一个文本串和一个模式串,求模式串在文本串中不重叠地出现了几次。若文本串和模式串中有许多部分是一样的,那么采用传统的方法就会有一些浪费。简单一点来说,kmp算法就是对模式串进行预处理,用一个next数组,next[j]的数值表示模式串的第j位之前的串中前多少位与最后多少位相等再加一,也就是如果第j位不匹配的话应该从第next[j]开始匹配。例如,
abcabx 对应的next数组的值为
011123
于是在匹配时
abcabc…
abcabx 发现不匹配
传统算法下
abcabc…
_abcabx
但在kmp中next[6] = 3,于是
abcabc…
___abcabx
我们已经知道第六位前面的两位ab与模式串头上的ab是一样的,于是就不用再检验一遍了,直接从第三位开始往后匹配。
这个算法还有可以改进的地方,我们让模式串不变,文本串变成
abcahx…
abcab… 匹配到这的时候发现不行,我们找next[5] = 2
abcahx
___ab… 由于前面是重复的,所以一定也不行
我们就直接在获得next数组的时候,如果t[i] == t[j]next[i] = next[j]。 这里也就是next[5] = next[2] = 1

好了,算法理解了之后写题遇到了什么问题呢
我习惯让数组从0开始存,这样的话next数组的第一位为0就不行了,会产生死循环 把它置成-1就好啦

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

char a[1005], b[1005];
int nextval[1005];

void get_next(char *t, int *nextval, int size)
{
    int i = 0, j = -1;
    nextval[0] = -1;
    while (i <= size)
    {
        if (j == -1 || t[i] == t[j])
        {
            i++;
            j++;
            if (t[i] != t[j])
            {
                nextval[i] = j;
            }
            else
            {
                nextval[i] = nextval[j];
            }
        }
        else
        {
            j = nextval[j];
        }
    }
}

int main()
{
    while (1)
    {
        scanf("%s", a);
        if (a[0] == '#' && strlen(a) == 1)
        {
            return 0;
        }

        scanf("%s", b);
        int sizea = strlen(a), sizeb = strlen(b);
        int ans = 0;

        get_next(b, nextval, sizeb);
        // for (int i = 0; i < sizeb; i++)
        // {
        //     printf("%d ", next[i]);
        // }
        // printf("\n");
        int i = 0, j = 0;
        while (i <= sizea)
        {
            if (j == -1 || a[i] == b[j])
            {
                if (j == sizeb - 1)
                {
                    i++;
                    j = 0;
                    ans++;
                }
                else
                {
                    i++, j++;
                }
            }
            else
            {
                j = nextval[j];
            }

            if (j >= sizeb)
            {
                ans++;
                j = 0;
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}

next被编译器认为时保留名称,所以就不能再作为数组名了,这个问题在我本地的gdb中没有报出来,交了好几个CE_(:з」∠)_,需要注意一下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值