KMP算法之Next数组——C#

这篇文章不解释什么是O(n)记法

KMP

kmp是一个两串字符串比较的算法,分别为P:模式串,S:文本串。

我的文章一般都是废话少说,直接就进入主题。

我们假设现在需要匹配如下:

p1

传统的做法:逐一的遍历 S 串,再遍历 P 串, S[ i ] != P[ j ] (i=0,j=0),因为不相等,所以 i 会自增 1 (++),j 回溯 0,当 i = 7 发生匹配,j++(j = 1), i = 8 发生匹配 j++(j = 2), i = 9 失配 j 回溯 0
p2

这边 P 串只有三个字符,还好,但是如果 P 串的字符量很大,这开销很大,因为我们要回溯 P 串到位置 0 然后开始新的匹配

然而KMP算法可以根据 P 串提前计算好预知的回溯位置,减少我们的回溯位,减少开销。也就是网上 所谓的 NEXT 数组

(这里我们不讨论什么时间复杂度,抛开这些理论,站在程序这一面来理解)

我们先看看NEXT 数组是怎么计算的。假设我们现在的 P 不变。
然后定义一个 int[] 数组,数组的长度的 P 串的长度 + 1(因为我们占用下 0 下标,并且数组的 0 号位标识为 -1 ,1号位标识为 0 ,因为我们的回溯字符 P 最高就是 0)。

先上下代码,然后继续讲解。

            _next = new int[p.Length + 1];
            _next[0] = -1;
            _next[1] = 0;

            int i = 0;
            int j = 1;

            while (j < p.Length)
            {

                if (p[i] == p[j] || i == 0)
                {
                    j++;
                    i++;

                    if (j < p.Length && p[i] != p[j])
                    {
                        _next[j] = i;
                    }
                    else
                    {
                        _next[j] = _next[i];
                    }
                }
                else
                {
                    i = _next[i];
                }
            }

这里的 i 表示的是前缀字符,j 表示的是后缀字符。
什么是前缀,什么是后缀?

1,2,3,4,5,6 => 3 前缀 1 后缀2
=> 5 (前缀1 后缀4)and (前缀2,后缀3)
类似高斯先生的算法 从1 加到 100

p3

我们可以手动演算一遍,方便牢记

这里的计算我并没有 计算 if (j < t.Length && t[i] != t[j]) 这个判断,这里是个小优化。

因为 假设我们有一串字符 S: SSSSSSSSSaaaCsssssdcacaaaaaGsscsssssssdac P:sssssdac

如果我们要进行匹配,我们可以大概看出,在匹配从C/G开始的时候就,会有开始的回溯,而且是一个一个的回溯,这样看起来不好,因为前面的 P 串的 sss..是相同的,我们可以考虑next数组保持一样的,这样我们就能直接回溯到指定的位置,从而减少回溯的次数。也就是 if (j < t.Length && t[i] != t[j]) 这个判断里面的语句了。

这里就是Next的数组计算了。

下篇再写后续的字符匹配

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值