Java 数据结构与算法系列精讲之KMP算法
作者:我是小白呀 发布时间:2023-05-06 14:55:55
标签:Java,KMP,算法,数据结构
概述
从今天开始, 小白我将带大家开启 Java 数据结构 & 算法的新篇章.
KMP 算法
KMP (Knuth-Morris-Pratt), 是一种改进的字符串匹配算法. KMP 算法解决了暴力匹配需要高频回退的问题, KMP 算法在匹配上若干字符后, 字符串位置不需要回退, 从而大大提高效率. 如图:
举个例子 (字符串 “abcabcdef” 匹配字符串 “abcdef”):
次数 | 暴力匹配 | KMP 算法 | 说明 |
---|---|---|---|
1 | a bcabcdef a bcdef | a bcabcdef a bcdef | a 和 a 匹配 |
2 | ab cabcdef ab cdef | ab cabcdef ab cdef | ab 和 ab 匹配 |
3 | abc abcdef abc def | abc abcdef abc def | abc 和 abc 匹配 |
4 | abca bcdef abcd ef | abca bcdef abcd ef | abca 和 abcd 不匹配, 回退. 暴力匹配回退到索引 1, 即 “b”, KMP 算法索引跳置 3, 即 “a” |
5 | ab cabcdef a bcdef | abca bcdef a bcdef | 暴力匹配 b 和 a 不匹配, 后移. KMP 算法 a 和 a 匹配 |
6 | abc abcdef a bcdef | abcab cdef ab cdef | 暴力匹配 c 和 a 不匹配, 后移. KMP 算法 ab 和 ab 匹配 |
7 | abca bcdef a bcdef | abcabc def abc def | 暴力匹配 a 和 a 匹配. KMP 算法 abc 和 abc 匹配 |
8 | abcab cdef ab cdef | abcabcd ef abcd ef | 暴力匹配 ab 和 ab 匹配. KMP 算法 abcd 和 abcd 匹配 |
9 | abcabc def abc def | abcabcde f abcde f | 暴力匹配 abc 和 abc 匹配. KMP 算法 abcde 和 abcde 匹配 |
10 | abcabcd ef abcd ef | abcabcdef abcdef | 暴力匹配 abcd 和 abcd 匹配. KMP 算法 abcdef 和 abcdef 匹配 , 匹配完成 |
11 | abcabcde f abcde f | abcabcdef abcdef | 暴力匹配 abcde 和 abcde 匹配. KMP 算法匹配完成 |
12 | abcabcdef abcdef | abcabcdef abcdef | 暴力匹配 abcd 和 abcd 匹配, 匹配完成. KMP 算法匹配完成 |
部分匹配表
部分匹配表 (Partial Match Table) 指的是 “前缀” 和 “后缀” 的最长共有元素的长度.
举个例子, 字符串 “ABCDABD” 的前缀与后缀:
字符串 | 前缀 | 后缀 | 共同部分 | 值 |
---|---|---|---|---|
A | NaN | NaN | NaN | 0 |
AB | A | B | NaN | 0 |
ABC | A, AB | C, BC | NaN | 0 |
ABCD | A, AB, ABC | D, CD, BCD | NaN | 0 |
ABCDA | A, AB, ABC, ABCD | A, DA, CDA, BCDA | A | 1 |
ABCDAB | A, AB, ABC, ABCD, ABCDA | B, AB, DAB, CDAB, BCDAB | AB | 2 |
ABCDAB | A, AB, ABC, ABCD, ABCDA, ABCDAB | D, BD, ABD, DABD, CDABD, BCDABD | NaN | 0 |
KMP 算法实现
重点:
KMP 算法中移动的位数 = 已匹配的字符数 - 对应的部分匹配值
import java.util.Arrays;
public class KMPMatch {
public static int Match(String str1, String str2, int[] next) {
// 初始化索引
int i = 0;
int j = 0;
for (; i < str1.length(); i++) {
if (j > 0 && str1.charAt(i) != str2.charAt(j)) {
// 不匹配, 回退
i = i - next[j - 1];
j = 0;
}
// 匹配
if (str1.charAt(i) == str2.charAt(j)) {
j++;
}
// 返回索引
if (j == str2.length()) {
return i - j + 1;
}
}
return -1;
}
// 部分匹配
public static int[] getNext(String s) {
// 定义数组
int next[] = new int[s.length()];
// 初始化i, j
int i = 0;
int j = -1;
next[0] = -1;
// 遍历
while (i < s.length() - 1) {
if (j == -1 || s.charAt(i) == s.charAt(j)) {
// 匹配成功
next[i] = j + 1;
i++;
j++;
} else {
//一旦不匹配成功j回退到-1
j = -1;
}
}
return next;
}
public static void main(String[] args) {
// 字符串1
String str1 = "BBCABCDAB ABCDABD";
// 字符串2
String str2 = "ABCDABD";
// 匹配表
int[] next = getNext(str2);
System.out.println(Arrays.toString(next));
// KMP算法
int result = Match(str1, str2, next);
System.out.println(result);
}
}
输出结果:
[0, 0, 0, 0, 1, 2, 0]
10
来源:https://iamarookie.blog.csdn.net/article/details/122105073


猜你喜欢
- 一、什么是HTTP协议HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应
- 1、问题描述关于java中的日志管理logback,去年写过关于logback介绍的文章,这次项目中又优化了下,记录下,希望能帮到需要的朋友
- Note:这篇文章是基于Android Studio 3.01版本的,NDK是R16。step1:创建一个包含C++的项目其他默认就可以了。
- C#程序自删除核心实现方法就是调用 cmd 传入命令行,等待几秒之后删除文件;应用程序在运行时,是不能将 exe 文件进行删除的。但是可以将
- 问题:对于多线程编程,很多时候往往需要向线程中传递多个参数,而C#中的线程只接收1个object类型的参数(如下):Thread t = n
- 只要是开发和手机通讯录有关的应用,总要学会获取联系人信息,每次都google很麻烦,怎么办?写一个工具类,获取到通讯录里所有的信息并分好类,
- 1.类的6个默认成员函数默认成员函数:用户没有显示实现,编译器会生成的成员函数称为默认成员函数。如果一个类中什么成员都没有,简称为空类。但空
- Settings是WebView提供给上层App的一个配置Webview的接口,每个WebView都有一个WebSettings,要控制We
- 一.求两直线交点class Point { double x; do
- Java for循环标签跳转到指定位置大家是否见过这种for循环,在for循环前加了个标记的:outerLoop:for (; ; ) {
- 示例 1 :使用搜索表单创建全屏模式我们要构建的小应用程序有一个应用程序栏,右侧有一个搜索按钮。按下此按钮时,将出现一个全屏模式对话框。它不
- 介绍MVC(Model-View-Controller)是一种软件架构模式,其中应用程序被划分为三个部分:模型(Model)、视图(View
- 效果图在开发APP中,经常要实现圆形头像,那么该如何实现呢?要裁剪吗,要重写draw函数吗?不用,只用一行代码就可以实现Glide实现圆形图
- 在 Spring 容器中,两个 Bean 之间除了通过 <ref> 建立依赖关系外,还存在着一些特殊关系。1 继承在
- 题目描述BM99 顺时针旋转矩阵描述 有一个NxN整数矩阵,请编写一个算法,将矩阵顺时针旋转90度。 给定一个NxN的矩阵,和矩阵的阶数N,
- package TOOLS;import java.io.BufferedReader;import java.io.File;import
- 算法效率在使用当中,算法效率分为两种,一是时间效率(时间复杂度),二是空间效率(空间复杂度)。时间复杂度是指程序运行的速度。空间复杂度是指一
- 在java程序开发中,ftp用的比较多,经常打交道,比如说向FTP服务器上传文件、下载文件,本文给大家介绍如何利用jakarta commo
- 本文实例讲述了Android编程中沉浸式状态栏的三种实现方式。分享给大家供大家参考,具体如下:沉浸式状态栏Google从android ki
- 我们在使用一些开源调度系统(比如:elastic-job等)的时候,对于任务的执行时间通常都是有规律性的,可能是每隔半小时执行一次,或者每天