【算法4】5.3.3.子字符串查找-KMP算法

KMP 是发明此算法的三个人名字首字母。(Knuth, Morris, Pratt)

暴力查找每次匹配失败时都需要回退指针 i,并重新对比已经检查过的字符。
KMP 通过对模式字符串进行预处理,生成一个确定有限状态自动机,
将文本字符串的字符依次放到自动机中,可以直接得到需要和文本字符串下一个字符 text.chatAt(i+1) 匹配的 j 的位置 pattern.chatAt(j)
即 j 应该向前移动一个位置(匹配的情况)或将 j 重置到之前的某个位置(不匹配的情况)。

可全屏查看代码

/**
* KMP 算法
* */
public class KMP {
private static final int R = 256; // 字母表
private int dfa[][]; // 确定有限状态自动机
private int M;
/**
* 对模式字符串进行预处理,生成确定有限状态自动机 dfa
* */
public KMP(String pattern) {
// 当匹配失败时,我们可以知道当前匹配的子串是 pattern[i-j, j],接下来需要匹配的子串是从 pattern[i-j+1] 开始
// 所以我们知道接下要放入自动机的字符,而将字符放入自动机又可以得到 j 的新值
// 所以在生成 dfa 的同时也在将模式字符串输入到自动机中,以此更新 X 的值
// dfa 的第一个索引表示的是输入的字符 c,第二个索引表示当前模式字符串的位置 j,值表示下一个状态(即需要将 j 重置到哪个位置)
M = pattern.length();
dfa = new int[R][M];
// 初始化自动机的状态,第一个字符匹配成功进入下一个状态,否则保持不动
dfa[pattern.charAt(0)][0] = 1;
// 从这里开始一边生成自动机,一边使用自动机
int X = 0; // 记录使用自动机的当前状态
for (int j = 1; j < M; j++) { // 在生成自动机时,从第二个字符开始使用自动机
for (int c = 0; c < R; c++) {
dfa[c][j] = dfa[c][X]; // 枚举字符集,并将每个字符放入自动机
}
dfa[pattern.charAt(j)][j] = j + 1; // 匹配成功进入下一个状态
X = dfa[pattern.charAt(j)][X]; // 将当前字符放入自动机,更新状态 X
}
}
/**
* 在文本中查找模式字符串
* */
public int search(String text) {
int N = text.length();
int i, j;
for (i = 0, j = 0; i < N && j < M; i++) {
j = dfa[text.charAt(i)][j];
}
if (j == M) {
return i - j;
} else {
return -1;
}
}
}

参阅

posted @   廖子博  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示