KMP算法(详细通俗的个人理解版)

1.KMP是什么?

一种字符匹配算法

2.它的优点是什么?

3.它的应用范围?

判断子母串关系以及各种需要寻找子串的题目

4.KMP的运行过程?

输入母串——>输入子串——>计算子串的next数组——>匹配

5.KMP与传统匹配算法的区别?

KMP的匹配逻辑与传统匹配逻辑相同,不同的是,当遇到字符不相同时,KMP进行的操作是从(匹配时的第一个字符的位置+当前不匹配字符的next数组值)的位置开始与子串的第(不匹配字符的next数组值)个字符进行新一轮的匹配

6.关键next数组的含义?

next数组中储存的数值表示的是以当前字符为末尾(不包含当前字符),前面一部分子串的首尾相同字符个数,如:(初始数next[0]为-1)absdab的next数值为1,aba为0,abcba为0,abc为0,ababa为2.

7.如何形象的理解KMP算法?

传统的字符匹配是每当字符不符合时,整体从母串的下一个位置重头开始进行操作(a为母串,b为子串)

for(int i = 0; i < a.length; i++){
    for(int j = 0, l = i; j < b.length; j++,l++){
        if(b[j] != a[l]){
            continue;
        }
        if(j == b.length - 1){
            printf("%d\n", l - b.length);//输出匹配成功时的第一个字符在母串中的位置。
        }
    }
}

而KMP则根据不符合字符的next数组的值来确定需要移动多少个位置再继续匹配,其余操作并无不同。

for(int i = 0; i < a.length; i++){
    for(int j = 0, l = i; j < b.length; j++,l++){
        if(b[j] != a[l]){
            i += next[j];
            continue;
        }
        if(j == b.length - 1){
            printf("%d\n", l - b.length);//输出匹配成功时的第一个字符在母串中的位置。
        }
    }
}

8.KMP算法的难点在哪?

经过上文的了解,我们发现貌似KMP也没有我们想象中的难,但其实不然,KMP算法的难点在于next数组的计算和匹配时的处理,细看之时,我们也可以发现next数组的计算貌似也是一个字符匹配的问题,因此我们需要在原来常规的匹配算法中进行改变,否则就无法达到我们提高程序运算效率的目的。

9.如何巧妙快速的计算next数组?

我们可以思考一下,当我们进行前后缀比较时是如何进行的,很明显,使用两个临时指针,一个指向头,另一个逐个后移匹配,当第一个字符匹配成功时,两者同时后移进行第二个字符的匹配,还需要考虑匹配完成时是否为末尾,否则不成立,继续进行原来的操作。

而next数组比较特殊,它需要得出每一个位置的最大前后缀的值,我们自然不能使用上面的传统方法,这与我们的初衷相悖。像这种连续操作的问题我们很容易想到循环和递归,接下来通过逐步分析来体会前人的智慧

字符串s = “ababaaab”;
初始化next[s.length - 1];
k = -1; j = 0;
next[0] = -1;
while(j < s.length - 1){
    if (k==-1 || t.data[j]==t.data[k]){ //k为-1或比较的字符相等时
        j++; k++;
        next[j] = k;
    }else{
        k = next[k];
    }
}

循环中的if比较是关键部分,循环以j的移动为循环运动过程,k的移动过程就是匹配过程,因为每一个next值都是当前字符串的最大前后缀的值(不包含当前字符),所以循环当移动到下一个字符时,k与j都是比较,的最新的字符,如果相符则加入最大前后缀中,然后继续进行循环也不需要从头匹配,如果不相符则将k移动到之前所求的最大前后缀的最后一个字符的next值所对应的字符串位置上,也是根据其最大前后缀(next[k])值进行位置判断,这就形成了一个递归模型。

如果还是觉得很抽象的话,大家可以根据代码,自己手写运算过程,就可以理解了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值