关于KMP算法的一点个人理解

原创 2007年10月01日 05:37:00
 
KMP算法解析
前些日子,我因为面试需要,温习了下KMP算法,结果瞪着书看了3个小时愣是没有怎么看懂,不得已,不得不
求助于网络,在网络上搜索了半天,大概上是能理解,可是对于程序中getnext函数中有条语句k=next[k], 我怎么都没有找着是怎么来的,而且网络上的解答都没有说明为什么是这样的,没有办法,我自己做下来,好好研究了下,终于知道了是怎么回事。下面就是我对这个算法的一些理解没,如果有什么错误,希望大家能一起讨论。也可以给我发电子邮件或QQ联系:
QQ:574860234
KMP算法是对传统的字符串模式匹配算法的一个改进,传统的字符串匹配其时间复杂度是O(m*n),而KMP算法则是O(m+n)。
首先看下传统的字符串模式匹配函数
int PatternMathch(char * str1,char * pat)
{
       int i=0,j=0;
       while(i < strlen(str1) && j < strlen(pat))
       {
              if(str[i] == pat[j])
{
       i++;
       j++;
}
else
{
       i = i – j + 1;
       j = 0;
}
       }
       if(j == strlen(pat))
return i– j;
       return -1;
}
 
 
 
从上面的函数中我们可以知道,每当模式串和主串中的某个字符匹配不成功的时候,都需要将主串回溯到该次匹配的下个字符处,而模式串都需要回溯到第一个字符处。如下图所示
下标:0   1   2   3   4   5   6   7   8   9   10
主串:a   b   a   b   a   c   c   d    e   a   a
模式:a   b   a   c   
当第3个字符进行匹配的时候,发现主串[3] != 模式串[3],
这时候,传统的模式匹配算法需要进行回溯。回溯后的结果如下所示:
下标:0   1   2   3   4   5   6   7   8   9   10
主串:a   b   a   b   a   c   c   d    e   a   a
模式:    a   。。。。   
即用主串的第二个字符与模式的第一个字符进行匹配,这时候,主串从第一个匹配失败的地方(下标为3)回溯到下标为1的地方,而漠视串也从下标为3的地方回溯到下标为0的地方重新开始下次匹配。因此,才会导致该算法的匹配最坏情况下为O(m*n),当然在一般的情况下,模式串并不是每次都匹配到最后一个字符的时候才发现不匹配的。但是下面这种情况将导致传统的字符串模式匹配达到最坏的情况。
主串: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab
模式串:aaaab
在上面这种情况下,每次的匹配都是在模式串的最后一个字符进行匹配的时候,发现不匹配,然后每次都在这个时候才进行回溯。
 
其实,从我们对前面的模式匹配过程可以发现,当第一次匹配不成功时,主串并不需要回溯到该次匹配的下个位置重新开始匹配。因为模式串[0]=模式串[2],当模式串[3]!=主串[3]的时候,前面的字符串子川p[0]。。。p[2] == s[0]。。。s[1]。这已经是匹配成功的。
所以此时主串不需要回溯到下个位置开始重新匹配,而可以直接用模式串的[1] 去和主串的[3]进行比较,而进行匹配。
下标:0   1   2   3   4   5   6   7   8   9   10
主串:a   b   a   b   a   c   c   d    e   a   a
模式:        a   b。。。。   
 
现在我们的任务就是要对一个模式串,得到其当某个字符匹配失败的时候,主串不动,而模式串向进行右移后下个开始和主串进行匹配的字符的下标位置。
下面我们完成对这个数组的定义,
其中next[j]中的j表示当模式串中的第j个字符和主串不匹配的时候,下次匹配,模式串下个开始和主串当前位置的字符进行比较的位置(下标)。
next[]的定义:
next[j]=
=-1                                                当 j=0 时 
=max{k|1<k<j且'P(1)...P(k-1)'='P(j-k+1)...P(j-1)'}当此集合非空时
=0 其它情况
 
根据定义。我们可以得到下面的求next数组函数
//pat表示模式串,next表示数组,长度和pat的长度一样。
int getnext(char * pat,int * next)
{
    int j=0,k = -1;
    next[0] = -1;
    while(j < strlen(pat))
    {
        if(k == -1 || pat[k] == pat[j])
        {
            j++;
            k++;
            next[j] = k;
        }
        else
            k = next[k];
    }
}
 
算法解释:
根据定义,next[0] = -1.
而假设当前next[j]=k已经求得,则求next[j+1]??
由于next[j]=k,表示
p(0)p(1)…p(k-1)p(k)…p(j-k)p(j-k+1)…p(j-1)p(j)中有
红色部分的相等,即
p(0)p(1)…p(k-1) = p(j-k)p(j-k+1)…p(j-1)。
此时,如果有p(k)==p(j)
next[j+1]=next[j]+1;
如果p(k) != p(j)
则剩下的任务就是要在p(0)…p(k-1)中找到一个子串p(0)…p(m) == p(j-m)…p(j-1)
而且p(m) == p(j)
因为之前已经有p(0)p(1)…p(k-1) = p(j-k)p(j-k+1)…p(j-1)。
所以要求子串p(0)…p(m) == p(j-m)…p(j-1),只要在p(0)…p(k-1)中找这个子串就可以了(这步想法很重要)。
因为假设存在m,满足p(0)…p(m) == p(j-m)…p(j-1)
p(j-m)…p(j-1)一定与p(k-m)…p(k-1)相等的。
所以相当于p(0)…p(k-m)…p(k-1)串中求next[k],
假设next[k]=m(这个是已经求出来的了。),表示
p(0)p(1)…p(m-1) = p(k-m)…p(k-1)
这个时候除了满足这点之外,还需要满足p(m) == p(j)
只有这两个条件都满足的情况下,这个时候
next[j+1]才能等于m,
假设还是不能满足p(m) == p(j)这个条件。
又由上面的结果已经知道
p(0)p(1)…p(m-1) = p(k-m)…p(k-1)
这个是成立的。
即在p(0)…p(m-1)p(m)…p(k-1)已经有m了(因为next[k]=m),
p(0)p(1)…p(m-1) = p(k-m)…p(k-1)
那么现在再在p(0)…p(m-1)中找个子串p(0)…p(n-1)与p(k-n)…p(k-1)相等
假设找到了n,
p(0)…p(n-1) == p(k-n)…p(k-1)
那么由前面的next[j]=k
可以知道p(j-n)…p(j-1) == p(j-n)…p(j-1)
如果这个时候又p[n] = p[j]的话,则满足条件了,否则可以继续递归下去。
 

关于RNN(Seq2Seq)的一点个人理解与感悟

自己在这近三个月的深度网络学习中的一点小感悟,希望对自己的后面学习和实验能有所启发。...
  • liuyuemaicha
  • liuyuemaicha
  • 2017年02月23日 22:27
  • 1985

KMP算法和BM算法

#include #include #include using namespace std; int KMPSearch(const string &str,const string &pa...
  • jeasn168
  • jeasn168
  • 2014年09月07日 21:16
  • 320

关于KMP算法的个人理解

最近准备接下来的校招面试,一直没学过数据结构的我,也不得不准备准备这方面的知识,对于字符串匹配这个课题,现在有很多的方法,然KMP确实其中经典的一种方法,这两天找了很多的相关资料,却发现理解很简单,而...
  • Cyanuestc
  • Cyanuestc
  • 2014年08月09日 17:09
  • 450

Latent Semantic Analysis (LSA) Tutorial 潜语义分析LSA介绍 六

WangBen 20110916 Beijing Part 4 - Clustering by Color 用颜色聚类 We can also turnthe numbers in...
  • yihucha166
  • yihucha166
  • 2011年09月20日 21:15
  • 2349

关于大数据的一些个人理解

前几天商学院的校友问了我几个关于大数据的问题,一看都是非常专业且典型的问题, 相信大家听这个词听得太多了也有很多疑问,于是我总结了下自己的理解,欢迎一起讨论。 1. 现在大数据很时髦,多大的数...
  • witforeveryang
  • witforeveryang
  • 2014年12月23日 20:02
  • 1095

KMP算法之我见:从运动角度理解next数组

人说MKP算法是最适合算法入门的了,可是它的next数组理解起来似乎不是那么容易,说真的它有点像C语言,入门有点难,但是只要理解了其中的精髓,你会发现并不禁惊叹“哦,真是太美妙了” 说明:本文,n...
  • abc_12366
  • abc_12366
  • 2018年02月01日 23:58
  • 97

KMP算法最浅显理解——一看就明白

说明KMP算法看懂了觉得特别简单,思路很简单,看不懂之前,查各种资料,看的稀里糊涂,即使网上最简单的解释,依然看的稀里糊涂。 我花了半天时间,争取用最短的篇幅大致搞明白这玩意到底是啥。 这里不扯概...
  • starstar1992
  • starstar1992
  • 2017年02月07日 17:41
  • 41034

KMP算法的个人理解

KMP算法个人理解
  • laocaixw
  • laocaixw
  • 2016年05月06日 21:14
  • 346

如果你看不懂KMP算法,那就看一看这篇文章( 绝对原创,绝对通俗易懂)

KMP算法之浅显易懂的阐述!
  • u011564456
  • u011564456
  • 2014年03月09日 20:32
  • 6388

KMP 算法的数学推导

不论从逻辑上怎么分析KMP算法,只要不给出具体的数学公式,都是不严谨的,直到看了KMP算法的数学公式,我才真正理解了该算法。            假设有一个待匹配的源字符串S,其数学表达式如下:  ...
  • chengonghao
  • chengonghao
  • 2016年07月21日 10:57
  • 509
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:关于KMP算法的一点个人理解
举报原因:
原因补充:

(最多只允许输入30个字)