关闭

KMP算法学习

标签: 算法kmp
233人阅读 评论(0) 收藏 举报
分类:

简单模式匹配最坏复杂度在:O(n*m)
KMP可以牛到在O(n+m)的时间数量级上完成串的模式匹配操作。
核心来了:
改进:每当一次匹配过程中出现字符比较不等时,不需要回溯i指针(主字符串),而是利用已经得到的”部分匹配”的结果将模式向右”滑动”尽可能远的一段距离,继续进行比较。

所以核心在于,向右滑动多少距离怎么计算。
终于搞得懂了,记录一下。

设主串是S,模式串是P。
用i指针在S串中游动,j指针在P串中游动。不用考虑i,j是从0开始计数还是从1开始计数。任选一个,这里我选择从1计数。
也即:S1S2S3….Sn
P1P2P3….Pm
上面我们说,核心在于失配时,模式串尽可能向右滑动远的一段距离
这是感性的说法,用可量化的语言描述是:当S[i] != P[j]时,i指针不要回溯,而是想,S[i]和P[k]再比较,这样只需要针对模式串进行研究

以下是数学推导:

失配时,已经部分匹配的是:P1P2…Pj-1 = Si-j+1Si-j+2…Si-1

注意下标。
假设此时应与模式中第k个进行比较,必须要满足的条件是:
模式串中前k-1个字符的字串必须和S[i]前面k-1个字符匹配。
即:

      P1P2...Pk-1 = Si-k+1Si-k+2…Si-1  (1)

此时让S[i]与P[k]比较,所以部分匹配满足:

      Pj-k+1Pj-k+2…Pj-1 = Si-k+1Si-k+2..Si-1  (2)

这里的j仍是当前未回溯的j的值。其实,在失配时:

    P1P2...Pj-1 = Si-j+1...Si-1,上面只是选取一部分与(1)可联立方程。

所以由(1) (2)可以推导出:

      P1P2…Pk-1 = Pj-k+1Pj-k+2…Pj-1(*)

也就得到了在失配时,如何仅仅根据模式串自身就能找到k的公式了。

P[1]=P[jk+1]P[2]=P[jk+2]P[3]=P[jk+3]...P[k1]=P[j1]

左边序号是升序,右边也是升序。因此,寻找的k值是:失配字符之前前缀和后缀相等的最大长度+1

特别注意k的含义是:指向下一个与文本串比较的在模式串中的位置,而前缀和后缀相等是公共部分,长度+1后才是k的位置。

令next[j] = k,我们就得到了常用的函数:

next[j] = 0, 当j = 1时
next[j] = max{k|1 < k < j 且P1P2…Pk-1 = Pj-k+1Pj-k+2…Pj-1,此集合不空}
next[j] = 1,其他情况

再次说明:next[j] 表示的是当模式中第j个字符与主串中相应的字符失配时,在模式中需要重新与主串中该字符串进行比较的字符的位置。

所以是基于j指针进行k的寻找,j是失配时候的值。

有了next[j]函数,那么匹配过程就可以描述为:

假设以指针i和j分别致使主串和模式中正待比较的字符,令i的初值为1.

若在匹配过程中,Si = Pj,则i++,j++
否则失配,i保持不变,j回退到next[j],即: j = next[j].再比较Si和Pj
若回退到j为0,则表示第一个字符就失配,此时需要主串的下一个位置开始于模式重新开始匹配。

以后再补代码。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:269434次
    • 积分:6689
    • 等级:
    • 排名:第3673名
    • 原创:398篇
    • 转载:1篇
    • 译文:1篇
    • 评论:109条
    最新评论