• KMP算法的动态规划解说


    理解我接下来所说的东西,需要大家懂得简单的动态规划。

    KMP大家都不陌生了,但是其中计算next数组总是搞不明白,我想有很多人和我一样。所以这里用动态规划的思路去描述一下这个问题。

    模式串P=c[1]c[2]......c[n]

    先设几个符号:

    suffix(S): S的所有后缀的集合

    prefix(S): S的所有前缀的集合

    例如:suffix("abcd") = {"","d", "cd", "bcd"}

             prefix("abcd") = {"","a", "ab", "abc"}

    看到,在这两个集合都除去了"abcd"本身。

    真对P定义next的意义:next[i]代表的意义是suffix(c[1]c[2]......c[i])与prefix(c[1]c[2]......c[i])两个集合中最长相同串的长度(不包括串c[1]c[2]......c[i])。那么如何计算next呢?其实这个计算过程类似动态规划的转移过程,从初始状态,不断的根据转移方程计算,直至计算出所有的可达状态。

    那么状态怎么定义?初始条件是什么?

    设两个游标p1,p2, p1,p2构成的位置对为状态<p1,p2>,例如p1在i位置,p2在j位置,i<j,那么状态<i, j>就代表c[1]c[2]......c[i]=c[j-i+1]c[j-i+2]......c[j],即串的前i个字符与后i个字符相同。之后我们根据<i,j>推出<i',j+1>。我们依次计算<i1, 1>,<i2,2>,......,<in,n>。设LMAX(<i, j>)=i,通过上面对next的定义,我们可知next[j]=MAX{LMAX(<i,j>)|0<=i<j}。

    初始化的条件为 next[1] = LMAX(<0, 1>) = 0。假设我们当前所在的状态为<i, j>,那么如何推出<i',j+1>呢?这必须得看c[i+1]与c[j+1]的关系,如果c[i+1]=c[j+1],那么我们到达<i+1,j+1>的状态;如果c[i+1]!=c[j+1],那么我们得根据所有可能的<i', j>状态,判断c[i'+1]=c[j+1]是否成立,如果成立就到达<i'+1,j+1>状态。那么,我们如何找到这些合法的<i',j>状态呢?很庆幸,因为next数组中天然的保存了我们需要的信息。当我们到达<i,j>这个状态并且发现c[i+1]!=c[j+1],那么下一个尝试的状态将是<next[i], j>,看看c[next[i]+1]=c[j+1]是否成立。而且我们发现,只要按照i,next[i],next[next[i]]......这样下去找到第一个能够符合转移条件的状态就OK了,如果没有一个能够使之转移的状态,就说明没有一个前缀和当前的某个后缀是相等的,那么直接跳转到<0, j+1>这个状态。

    举个例子吧: S=abcababc
    
    为了方便理解,在S前加一个通配符$
    
    $abcababc          <0, 1>             next[1]=0
    ||
    
    $abcababc          <0, 2>             next[2]=0
    | | 
    
    $abcababc          <0, 3>             next[3]=0
    |  |
    
    $abcababc          <1, 4>             next[4]=1
     |  | 
    
    $abcababc          <2, 5>             next[5]=2
      |  |
    
    下一步s[3]!=s[6],这将尝试状态<next[3],j>=<0,j>,使之转移到下面的状态
    
    $abcababc          <1, 6>             next[6]=1
     |    | 
    
    $abcababc          <2, 7>             next[7]=2
      |    |
    
    $abcababc          <3, 8>             next[8]=3
       |    |

    到此,有的同学又有疑问了,人家KMP定义的next[i]的意义和你的也不一样呀。对,确实不一样。

    KMP中对next[i]的定义为:设文本串为T,模式串为P,p[i]!=T[j]时,应该用p[?]与T[j]进行比较。

    对应于上例,得到的next数组值应为

    KMP的next: -1 1 1 1 2 3 2 3
    我们的next:  0 0 0 1 2 1 2 3

    怎么通过我们的next获取到正确的next呢?非常简单,从后往前循环做next[i] = next[i-1]+1,之后next[1]=-1就哦了。

  • 相关阅读:
    2020学习 04 python 爬取某政府网站信件
    2020学习03
    2020学习02
    阅读笔记--《一线架构师实践指南》--Pre-architecture阶段
    重构“信息领域热词分析”,实现六种质量属性战术
    pycharm错误:Error updating package list: connect timed out解决
    python连接mysql数据库——编码问题
    阅读笔记--《大型网站技术架构》—02架构
    python查询MySQL数据库的表以及所有字段
    python连接mysql数据库——版本问题
  • 原文地址:https://www.cnblogs.com/haolujun/p/2728015.html
Copyright © 2020-2023  润新知