关闭

KMP next数组讲解

176人阅读 评论(0) 收藏 举报

本文只讲解KMP子串keyString(下标用j表示),中和源字符串SoureceString(下标i表示)某次匹配失败后。下次匹配j的取值。
关于KMP算法入门可以看看其他博文(最主要网上关于这个算法写烂了,我这里只记录下我学习不懂的地方)

前言

在学KMP算法的时候一直感觉next数组的实现是让我最头痛的。所以现在回过头写下笔记,方便以后再看。

规则:
1. keyString(子串)的next数组大小为keyString的长度。
2. next第一个元素为-1
3. next数组下标数等于 子串前缀和后缀的匹配数

前缀概念:
子字符串的从第一个元素开始到第x元素 和 字符第y个元素到最后一个字符串相等.(x和y可以相等)

注意 后缀的概念:有个误区 是指子字符串第z个元素的时候 把z最为最后一个元素

eg:
字符串 keyString =“abcabcx”

这里写图片描述

我们可以把.下标为1的元素(即是第二个元素)作为后缀。那么前缀是a。后缀是b
我们把下标为5的元素作为后缀。那么前缀是abc(下标为0,1,2)后缀是abc(下标为 3,4,5)

上面对应next数组
这里写图片描述
当子串到下标为6的位置和源字符串匹配失败的时候,下次匹配直接到下标为3的位置

ok 现在我们开始现实某个字符串next数组的实现,首先写一个方法为get

    //java语言
    // T为子字符串
    // next数组 
    // 当方法结束的时候 next包含对应T的射影数值
    public static void get(String T, int[] next) {
    ....
    }

我们先实现前两个规则

规则:
1. keyString(子串)的next数组大小为keyString的长度。
2.  next第一个元素为-1

如下

//默认传入的next数组大小为子字符串大小 所以实现规则2即可
public static void get(String T, int[] next) {

        int i, j;

        j = -1;
        next[0] = -1;
        i = 0;

    }

最后一个规则:

next数组下标数等于 子串前缀和后缀的匹配数.先看一下next完成的案例在说

算法核心也在这此处,再回头看看如下字符串和对应next数组
这里写图片描述

理解next数组的含义
我们看一下‘x’对应next为6
意味着:
1. 字符串从0到5作为前缀。(为什么不到6?因为数组下标从0开始)
2. 从x下标减6开始到x前面一个数作为后缀。
3. 有6个循环数。
这里写图片描述

先看最终代码(可能会疑惑在回溯部分,先暂时看看后面再解释):

 public static void get(String T, int[] next) {

        int i, j;

        j = -1;
        next[0] = -1;
        i = 0;
        while (i < T.length() - 1) {

            if (j == -1 || T.charAt(i) == T.charAt(j)) {

                i++;
                j++;
                next[i] = j;
            } else {
                j = next[j];//回溯
            }
        }
    }

关于回溯我们举例说明说明

我们假设数组末尾追加一个字母d(下标为10)

这里写图片描述

假设我们的算法遍历到下标为10 数值为x的元素。
此时

j=6. i = 9

此时算法 T.chatAt(i) 不等 T.chatAt(j)所以走else路径

 j = next[j];//回溯
  • 将j回溯到next[6]的位置,如果此时相等那么 即T.chatAt(i)== T.chatAt(j)。那么就结束了。不然继续回溯。我当时在想为什么j会回溯到next[j]。原因如下,j代表着有多少个后缀和前缀数相等的数量。那么我们将设 下标为10(数值x)的元素等于下标为6(数值a)的元素 。循环到此的时候j=6代表着在下标为9的元素之前有6个相等数。(0,1,2,3,4,5 和 3,4,5,6,7,8)。那么6 和 9 相等就代表着相同后缀有6个。所以我们只需要判断字符串6和9即可(因为此算法如果前面的数字前缀相等那么会建立再次基础上 进行判断【j= 6 就是一个基础,它代表着 前缀的后面一个数 也代表着前缀和后缀相同数】)。

  • 那么假设不相等的情况的解释:
    继续假设运行到
    我们的算法遍历到下标为10 数值为x的元素。
    此时

j=6. i = 9

(0,1,2,3,4,5 和 3,4,5,6,7,8前面判断已经相等),但是数组下标6和9不相等 进行j回溯到next[6]的位置,也就是 j = 3 的位置( next[6] = 3),
j代表某前缀的最后一个数的后面一个数。比如说 j =3 那么前缀就是 0 1 2。我们在我们 j =6 i =9 匹配失败后 你可以让 j = j-1继续匹配 T.chatAt(9),但是这是多余的。

假设 数组下标6 和9 匹配失败 进行 j=j-1
T.chatAt(6) != T.chatAt(9);
j = j-1 = 5;
那么
T.chatAt(5) == T.chatAt(9);
也就是if判断条件成立 可得
0 1 2 3 4 5 和 4 5 6 7 8 9相等.
那么可以得以下结论:
T.chatAt(5) == T.chatAt(9);
T.chatAt(5) == T.chatAt(8);
T.chatAt(8) == T.chatAt(9);
这三个不难推理出

继续
T.chatAt(4) == T.chatAt(8);
T.chatAt(9) == T.chatAt(4);
T.chatAt(9) == T.chatAt(5);

也就是 7==8==9 和 1==2==3

最终你将推出 0==1==2==3==4==5 ==7==8==9
显然这会和next数组原有数组数值发生冲突。顾不能直接j= j-1。当然如果数组前缀和后缀所有元素都相等 时候可以推出next[j] = j -1

0
0
查看评论

KMP算法next数组的理解

KMP算法的基础部分不再多说,详细大家都Google过了。这里做一些总结。 对于KMP算法来说,重点就是 next数组 (也有叫覆盖函数,部分匹配表,lps数组等)。 总之就是 对模式串做预处理,而且该预处理只和 模式串(pattern)本身有关! 假设有模式串 patt...
  • u012846486
  • u012846486
  • 2014-05-04 16:06
  • 1634

KMP的next数组求法详解

近几天学习kmp算法,在next数组求解上受苦颇深,看了不少博客,感觉写得都不够清晰,所以想按照自己理解的过程来尝试写一下,也便于以后温习。
  • to_be_better
  • to_be_better
  • 2015-10-13 00:51
  • 3762

vijos kmp next数组应用

https://vijos.org/p/1677背景 陶陶是一个智能机器人,他能像人一样思考问题,不过由于IQ问题,他给自己取了一个很长很长的名字。 描述 某一天,陶陶想把自己的名字涂在墙上。由于他的名字太长,为了省事,他从自己名字的开头截取了一段作为模板。我们不妨设这个模板的长度为l,陶陶的...
  • zjy2015302395
  • zjy2015302395
  • 2016-10-10 01:18
  • 266

KMP入门级别算法详解--终于解决了(next数组详解)

从几个月之前就开始学习KMP,看了一堆博客跟教程,没有一个整明白。后来找了大神给我口述的,才算是明白了。我用简练的语言再重新描述一下,抛开算法的代码实现,就概念理论来阐述KMP算法。 next数组详解 首先是理解KMP算法的第一个难关是next数组每个值的确定,这个问题困恼我很长时间,尤其是对照着代...
  • LEE18254290736
  • LEE18254290736
  • 2017-08-16 22:55
  • 3068

KMP算法next数组计算方法的优化

KMP算法的原理就是利用相匹配的前缀子串与后缀子串,来确定失配时下次对齐的位置; 其中最关键的就是next数组的确立; 数据结构课本上经典的例子: void getNext(const char *pStr, int *nextArr) { int i = 0, k = -1, pLen = s...
  • sowhat_Ah
  • sowhat_Ah
  • 2014-12-26 11:34
  • 18030

KMP算法及next数组详解

最近整理笔记时,突然翻出几年前理解起来困难无比的看毛片(KMP)算法,笔记中详述了搜索过程,图文并茂,然而在最最重要的next数组部分却是一带而过,于是找出当年的教材,也只是写了getnext()函数,想着上网找一找图文并茂的举例,结果这一找彻底蒙比,众说纷纭,同样一个子串,处理得到的“next数组...
  • u012043391
  • u012043391
  • 2016-10-14 18:21
  • 2412

KMP算法next数组生成中k=next[k]解释

本文适用于读者对KMP算法有一定的了解void initNextArray(string p){ int k = -1; int j = 0; next[0] = -1; while(j < p.size()-1){ if(k == -1 || ...
  • BaiDingLT
  • BaiDingLT
  • 2017-04-09 12:14
  • 836

数据结构:KMP next数组求串最小循环节、循环周期

KMP中next数组用于求最小循环节的应用 之前不知道next还有这个
  • u011639256
  • u011639256
  • 2014-08-14 16:10
  • 1294

KMP算法中next数组的求取

前两篇博客分别介绍了KMP算法的理论基础及代码实现,但是KMP算法实现的核心在于next数组的求取,第一篇论文中介绍了next数组的手动求取方法;第二篇博客中介绍了代码实现,当时没有讲清楚,而且代码实现存在一定问题。本篇博文将详细介绍next数组的求取办法及代码实现。
  • u011028771
  • u011028771
  • 2016-11-01 10:03
  • 4244

对kmp算法next数组的一些简单理解

一 引言    先不说kmp算法,先谈谈朴素的模式匹配算法。朴素的模式匹配算法是一种暴力匹配算法,也就是最蠢的匹配算法。如果失配的话,i,j都得变,i回溯至刚开头字符的下一位,j就置为0。这就造成了浪费,因为i已经回溯到刚才比较过了的字符,又需要再一次被比较,重复比较,造成浪费...
  • s150503
  • s150503
  • 2017-02-27 19:12
  • 179
    个人资料
    • 访问:491611次
    • 积分:6794
    • 等级:
    • 排名:第4126名
    • 原创:274篇
    • 转载:63篇
    • 译文:0篇
    • 评论:51条