【KMP算法原来这么简单啊】

KMP:字符串匹配算法

目的:希望在字符串匹配过程中,遇到不能匹配的字符时 尽可能把模式串(搜索的字符串)多往后移动几位。

思路:用已知推未知

例如:下面两字符串比较到第7个字段时,发现不匹配,常规匹配法把模式串往后移动一位再进行比较,而KMP可以将字符串往后移动3位,对于这种已匹配模式串包含公共子串的场景,是不是这样更高效一点呢。

主串:abcabcabcdx
模式串:abcabcdx
常规匹配主串:abcabcabcdx
模式串:  abcabcdx
KMP主串:abcabcabcdx
模式串:      abcabcdx

其实这都要归功于next数组,比如上面的示例程序,在下标 6 处发现不匹配,通过next(5) 得到下标 2,也就是主串位置5 对应 模式串的位置 2,后面我们从6 和 模式串 3开始比较。

为啥是next(5)呢?因为下标6前面的才是已经比较过的,属于已知,已知串中如果有公共前缀子串才能用next数组跳转。下面是next数组的示例程序,可以参考下。

生成next数组示例程序:

// b表示模式串,m表示模式串的长度 
var b = 'abcabcabxabcabcabxy'.split('');
function getNexts(b, m) {
    var next = [];
    next[0] = -1;
    var k = -1;
    for (var i = 1; i < m; ++i) {
        while (k != -1 && b[k + 1] != b[i]) {
            k = next[k];
        }
        if (b[k + 1] == b[i]) {
            ++k;
        }
        next[i] = k;
    }
    return next;
}
getNexts(b,b.length);

next数组生成过程像是动态规划的思想,每一个字符都基于前一个字符已经匹配的位置再继续向下匹配的,不需要从头开始匹配。例如下图生成的next数组。

  1. 前3个字符一眼看过去没有公共子串,我们先跳过。
  2. 从下标3 的第4个字符开始,我们发现 a 与 下标为 0 的 a一样,所以next[3] = 0。(其实这个过程是先看了一下他前面的next[2] 发现是-1,没法继续匹配,所以跳转到第一个字符重新开始)
  3. 当处理到下标为4的字符 b 时,先看一下前面的 next[3] = 0,噢原来下标3与下标 0字符一样,所以可以从下标 1 处开始比较,发现也一样 next[4] = 1,后面字符以此类推。这种动态规划的方式是不是前面公共子串越长,节省的比较次数越多呢!

next数组生成 和 匹配过程中的跳转示例图:

文章如何有错误的地方,欢迎大家留言指正。

朋友们如果有好的算法学习方法也可以留言讨论啊!一起学习,一起进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值