zoukankan      html  css  js  c++  java
  • KMP算法

    关于KMP算法,看了很多博客,自己也做了一些字符串匹配之后,总算弄懂一些了,但是可能还要进一步深入研究,先写一部分吧,这部分足够应对笔试的nextval和next问题了。

    关于如何求next:

    先给出一个字符串“ababaabab”

        j         1  2  3  4  5  6  7  8  9

        i         a  b  a  b  a  a  b  a  b

      next     0  1  1  2  3  4  2  3  4

    nextval   0  1  0  1  1  4  1  0  1

    next怎么求呢:

    首先,要了解两个概念:"前缀"和"后缀"。 "前缀"指除了最后一个字符以外,一个字符串的全部头部组合;"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。

    "部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例,

      - "A"的前缀和后缀都为空集,共有元素的长度为0;

      - "AB"的前缀为[A],后缀为[B],共有元素的长度为0;

      - "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;

      - "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;

      - "ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A",长度为1;

      - "ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB",长度为2;

      - "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。

    其实在我看来,撇开这个next值在KMP中的正式含义,如果要便于理解,你可以看做后缀中跟前缀的最长共有元素,我们要求的就是这个共有元素加上轮到的字符,得到“最终串”,然后看“最终串”有多长(其实就是看最后一位的位置,变相求字符串长度),就是所求的next值。

    关键是理解我说的共有元素,要理解我说的通俗的共有元素,就要看懂上面对前缀和后缀以及“部分匹配值”,所以先看懂啥是共有元素后,再继续往下,我相信你一定能学会。

    我个人是很讨厌各种专业名词混杂的博客的,十分不方便理解,所以我尽量用通俗的方式来解释。

    我们先看到第一个字符a,此时j=1,求的是next(1)。next(1)为该字符串的第一个字符,它之前没有别的字符,所以不用比较,所以为0。

    接着是轮到第二个字符b, 此时j=2,求的是next(2)。next(2)为该字符串的第二个字符,它之前的字符串为“a”,a中没有重复的字符,所以共有元素为空,那么加上轮到的字符“b”,得到的“最终串”为“b”,长度为1,且,那next(2)= 1。

    总之,不管前两位是什么,next(1)、next(2)都固定为 0、1。

    轮到第三个字符a了,它前面是字符串“ab”,很明显字符串“ab”中不含重复字符,所以共有元素为空,那么加上轮到的字符“a”,得到的“最终串”为“a”,长度为1,且,那next(3)= 1。

    轮到第四个字符b了,它前面是字符串“aba”,很明显字符串“aba”中含重复字符,共有元素为“a”,那么加上轮到的字符“a”,得到的“最终串”为“b”,长度为2,且,那next(4)= 2。

    轮到第五个字符a了,它前面是字符串“abab”,很明显字符串“abab”中含重复字符,共有元素为“ab”,那么加上轮到的字符“a”,得到的“最终串”为“aba”,长度为3,且,那next(5)= 3。

    轮到第六个字符a了,它前面是字符串“ababa”,这时,你要是不理解上面的前缀后缀,我觉得你就嗝屁了,字符串“ababa”存不存在共有元素呢?有的话,是什么呢?"ababa"的前缀为[a, ab aba, abab],后缀为[a,ba,aba,baba],这下看得出来了吧,共有元素取最长是“aba”,加上第六个字符a,最终串为“abaa”,所以next(6)= 4。

    以此类推,应该没问题吧,关键是搞懂前缀和后缀。

    那么next讲完,我们再来说说nextval,看了贼多关于nextval的求法,真的脑袋疼,最后我找到了一个我特别喜欢的,这里跟大家分享一下:

    关键在于只看前面有重复字母的几位就可以。

    比如上面这个字符串ababaabab吗,我们复制粘贴一下,这样方便大家看:

    先给出一个字符串“ababaabab”

        j         1  2  3  4  5  6  7  8  9

        i         a  b  a  b  a  a  b  a  b

      next     0  1  1  2  3  4  2  3  4

    nextval   0  1  0  1  1  4  1  0  1

    这里我们已经能熟练求出next了,这时候其实工程已经完成一大半了,接下来就是我跟你们说的关键——只看前面有重复字母的,其余跟next一样:

    可见从第三位开始都有重复字母,那么前两位nextval就是0、1了,好,我们开始从第三位开始求:

    第三位是“a”,它的next值为1,就找字符串的第1位字符,是“a”,一样,那就把这个a的nextval值改为后面这个“a”的next值 0 。

    第四位是“b”,它的next值为2,就找字符串的第2位字符,是“b”,一样,那就把这个a的nextval值改为后面这个“b”的next值 1 。

    第五位是“a”,它的next值为3,就找字符串的第3位字符,是“a”,但第三位的这个a之前做过处理,所以就把第五位的这个a的nextval值改为第一个“a”的next值 0。

    第六位是“a”,它的next值为4,就找字符串的第4位字符,是“b”,诶!不一样,这时候就把nextval等于next就行,所以第六位的next值 为4 。

    以此类推。

    最后是KMP算法的原理,就是KMP匹配串如何移动,每次移动多少的问题。这一块我觉得有个博客写的比我好很多,在这里贴出来,我觉得写的已经十分通俗易懂了。关于前缀后缀和共有元素部分我也略有借鉴,感谢这位博主。

    http://www.cnblogs.com/c-cloud/p/3224788.html

  • 相关阅读:
    SpringApplication类-1
    post与head注入
    sql_post注入
    渗透测试点线面合集
    渗透入侵溯源
    VMware 安装Tools 失败的问题:VGAuthService 启动失败
    Weblogic wls-wsat XMLDecoder 反序列化漏洞复现(CVE-2017-10271)
    web常见的中间件漏洞及复现
    XX点评H5字体映射
    python控制阿里云服务器开机,关机,重启
  • 原文地址:https://www.cnblogs.com/Misakikure/p/9755578.html
Copyright © 2011-2022 走看看