KMP字符串匹配

博主记录自己理解的KMP算法,提到KMP的精妙在于next数组,其保存字符串前后缀相似度。求next数组核心是j的回溯,求出next数组后KMP较易理解。还指出next数组有缺陷,介绍了改进的nextval可提前判断回溯点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本蒟蒻经过一下午的挣扎终于能略微窥探到KMP算法的精妙,也是弥补了以前学数据结构的遗憾,这里记录一下蒟蒻自己理解的KMP算法,博客简略,主要是大概过一下,让自己以后能回忆起来,具体参考《大话数据结构》


KMP的精妙之处就在于它的next数组,next[i]保存的是第\(i\)个数之前的字符串前后缀相似度,也可以理解为上一个可匹配的前缀字符串下一个字符。求next数组的算法核心就在于\(j\)的回溯,他可以回溯到之前的最长可匹配前缀字串,因为这样后缀字串就为对应的最长可匹配后缀字串,至于为什么手动模拟一遍\("ababcabababc"\)就知道了(滑稽)。

上代码:

/*求子串T的next数组*/
void get_next(string T, int *next)
{
    int i = 1, j = 0;
    next[1] = 0;//守字母next赋值0
    while (i < T[0])//T[0]储存子串T长度
    {
        if (j == 0 || T[i] == T[j])
        {
            i++;
            j++;
            next[i] = j;
        }
        else
            j = next[j];//字符不相同,回溯
    }
}

求出了next数组,接下来的KMP就比较好理解了,只回溯\(j\),不回溯\(i\)

int index_KMP(string S, string T, int pos)//返回匹配到的下标
{
    int i = pos;//pos为S主串开始匹配的位置
    int j = 1;
    int next[255];
    get_next(T, next);
    while (i <= S[0] && j <= T[0])//i,j小于两个字符串的大小
    {
        if (j == 0 || S[i] == T[j])//和传统匹配算法相比增加特判
        {
            i++;
            j++;
        }
        else
            j = next[j];
    }
    if (j > T[0])
        return i - T[0];//返回S中匹配字符串的开头位置
    else
        return 0;//匹配失败
}

但是next数组还是有缺陷,比如主串为\("aaabcde"\),子串为\("aaaaax"\),当\(i=5,j=5\)的时候\(a,b\)不相等,那么\(j\)会从5,4,3一步一步回溯到1,造成时间的浪费,所以下面的nextval是一种提前判断回溯点,如果回溯点和原来的一样要回溯就直接回溯到最终位置了。

/*求子串T的nextval数组*/
void get_nextval(string T, int *nextval)
{
    int i = 1, j = 0;
    nextval[1] = 0;//守字母next赋值0
    while (i < T[0])//T[0]储存子串T长度
    {
        if (j == 0 || T[i] == T[j])
        {
            i++;
            j++;
            if (T[j] != T[j])//当前字符的前缀字符不同
                nextval[i] = j;//正常赋值
            else//当前字符前缀字符相同,将前缀字符的nextval值赋给在i上的值
                nextval[i] = nextval[j];
        }
        else
            j = nextval[j];//字符不相同,回溯
    }
}

转载于:https://www.cnblogs.com/JMWan233/p/11161795.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值