让你快速掌握KMP算法的最简详解 —— 动态规划、有限状态自动机(DFA)

KMP算法

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)。

文章正式开始之前

做如下说明
表格模板

  1. PAT: 模式串,如 ABAACA也就是想要查找的结果。
  2. CharAt: 这里ABC是指当前用来匹配Pat的字符,比如这里有一串文本ABABABC。就是在ABC这三个字符构成的文本串里面寻找内容,取3个字母是为了精简说明过程。
  3. 状态(M): 当前匹配的状态。
  4. 前一个状态(X): 记录如果失败了应该 保留 到哪些步骤之前。
  5. dp: 构建的状态转移数组,即表格内容。

解释

整体的流程图

取自《算法(第4版)》图5.3.6

构建一个状态表,当在某个状态时,遇到了某个字符下一步应该转移到什么状态
取自算法第四版
j=0这个位置成功匹配到A,说明可以前往(Next)状态1

CharAt A✔️ Next
Pat A✔️ B A B A C
J 0 1 2 3 4 5

j=1这个位置成功匹配到B,说明可以前往(Next)状态2

CharAt A✔️ B✔️ Next
Pat A✔️ B✔️ A B A C
J 0 1 2 3 4 5

那么在 j=1这个位置与A不匹配(B才能成功),说明可以前往状态1

CharAt A✔️ A❌
Pat A✔️ B❌ A B A C
J 0 1 2 3 4 5

此时保留Pat的第一位A可以与CharAt的第二位A匹配,继续匹配下一个位置的字符串不需要回退在CharAt上的文本指针。

CharAt A A✔️ Next
Pat A✔️ B A B A C
J 0 1 2 3 4 5
如何构建这个转移过程

我们将以 ABAACA来构建这个过程。

正确转移到最后一个状态,即已经匹配成功

ABAACA构建一个最简单的状态转移图片,它的意思是:
状态0匹配到字符A转移到状态1,在状态1匹配到字符B转移到状态2
直到在状态4匹配到字符C转移到状态5则获取结果成功。这是一条目前最容易定义的转移方式。
成功转移

圆圈内的数子代表当前状态

那么为什么这么定义呢?

  1. 可以看到如想要到达状态2,必须已经满足状态1又成功匹配了B字符。
  2. 那么当想要到达状态6,必须已经满足状态5又成功匹配了A字符,也就是当前已经成功匹配了Pat(ABAACA)
  3. 后面的每一层状态都是由之前状态决定,所以可以从前往后计算下一步应该转移成什么状态,符合 动态规划 的过程。
转移过程的代码

构建转移表的过程

for 0 <= j < M: // 状态由模式串决定
    for 0 <= c < 256: // 也可以是更大的包括中文等
        dp[j][c] = next //下一步应该前往什么状态

识别过程

int M = 0//当前初始状态
int P = pat.length();//模式串的长度,也就是总共具有多少状态,[0...P]一共是P+1个状态
int T = txt.length()//计算文本的长度
for (int i = 0; i < T; i++) {
   
	M = dp[M][txt.charAt(i)];//当前状态在遇到某个字符应该转移到哪里
	if (M == P) {
   //当到P这个状态的时候已经满足条件,返回成功的位置
		return i - M + 1;
	}
}
匹配成功转移表

匹配成功转移表

  1. 状态0匹配到第一个字符A,此时模式串与字符匹配表示可以前往
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值