视频讲解:https://www.bilibili.com/video/av49930100?from=search&seid=6859172222314383143
leetcode的简单kmp题:
https://leetcode-cn.com/problems/implement-strstr/solution/kmp-suan-fa-xiang-jie-by-labuladong/
为了描述状态转移图,我们定义一个二维 dp 数组,它的含义如下:
dp[j][c] = next0 <= j < M,代表当前的状态0 <= c < 256,代表遇到的字符(ASCII 码)0 <= next <= M,代表下一个状态dp[4]['A'] = 3 表示:当前是状态 4,如果遇到字符 A,pat 应该转移到状态 3dp[1]['B'] = 2 表示:当前是状态 1,如果遇到字符 B,pat 应该转移到状态 2
根据我们这个 dp 数组的定义和刚才状态转移的过程,我们可以先写出 KMP 算法的 search 函数代码:
public int search(String txt) {int M = pat.length();int N = txt.length();// pat 的初始态为 0int j = 0;for (int i = 0; i < N; i++) {// 当前是状态 j,遇到字符 txt[i],// pat 应该转移到哪个状态?j = dp[j][txt.charAt(i)];// 如果达到终止态,返回匹配开头的索引if (j == M) return i - M + 1;}// 没到达终止态,匹配失败return -1;}
构建状态转移图
回想刚才说的:要确定状态转移的行为,必须明确两个变量,一个是当前的匹配状态,另一个是遇到的字符,而且我们已经根据这个逻辑确定了 dp 数组的含义,那么构造 dp 数组的框架就是这样:
for 0 <= j < M: # 状态for 0 <= c < 256: # 字符dp[j][c] = next
这个 next 状态应该怎么求呢?显然,如果遇到的字符 c 和 pat[j] 匹配的话,状态就应该向前推进一个,也就是说 next = j + 1 。
如果字符 c 和 pat[j] 不匹配的话,状态就要回退(或者原地不动),我们不妨称这种情况为状态重启
