Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之KMP算法
概述
從今天開始, 小白我將帶大家開啟 Java 數(shù)據(jù)結(jié)構(gòu) & 算法的新篇章.

KMP 算法
KMP (Knuth-Morris-Pratt), 是一種改進(jìn)的字符串匹配算法. KMP 算法解決了暴力匹配需要高頻回退的問題, KMP 算法在匹配上若干字符后, 字符串位置不需要回退, 從而大大提高效率. 如圖:

舉個例子 (字符串 “abcabcdef” 匹配字符串 “abcdef”):
| 次數(shù) | 暴力匹配 | KMP 算法 | 說明 |
|---|---|---|---|
| 1 | abcabcdef abcdef |
abcabcdef abcdef |
a 和 a 匹配 |
| 2 | abcabcdef abcdef |
abcabcdef abcdef |
ab 和 ab 匹配 |
| 3 | abcabcdef abcdef |
abcabcdef abcdef |
abc 和 abc 匹配 |
| 4 | abcabcdef abcdef |
abcabcdef abcdef |
abca 和 abcd 不匹配, 回退. 暴力匹配回退到索引 1, 即 “b”, KMP 算法索引跳置 3, 即 “a” |
| 5 | abcabcdef abcdef |
abcabcdef abcdef |
暴力匹配 b 和 a 不匹配, 后移. KMP 算法 a 和 a 匹配 |
| 6 | abcabcdef abcdef |
abcabcdef abcdef |
暴力匹配 c 和 a 不匹配, 后移. KMP 算法 ab 和 ab 匹配 |
| 7 | abcabcdef abcdef |
abcabcdef abcdef |
暴力匹配 a 和 a 匹配. KMP 算法 abc 和 abc 匹配 |
| 8 | abcabcdef abcdef |
abcabcdef abcdef |
暴力匹配 ab 和 ab 匹配. KMP 算法 abcd 和 abcd 匹配 |
| 9 | abcabcdef abcdef |
abcabcdef abcdef |
暴力匹配 abc 和 abc 匹配. KMP 算法 abcde 和 abcde 匹配 |
| 10 | abcabcdef abcdef |
abcabcdef abcdef |
暴力匹配 abcd 和 abcd 匹配. KMP 算法 abcdef 和 abcdef 匹配 , 匹配完成 |
| 11 | abcabcdef abcdef |
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 算法實現(xiàn)
重點(diǎn):
KMP 算法中移動的位數(shù) = 已匹配的字符數(shù) - 對應(yīng)的部分匹配值
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) {
// 定義數(shù)組
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);
}
}
輸出結(jié)果:
[0, 0, 0, 0, 1, 2, 0]
10
到此這篇關(guān)于Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之KMP算法的文章就介紹到這了,更多相關(guān)Java KMP 算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java數(shù)據(jù)結(jié)構(gòu)之哈夫曼樹概述及實現(xiàn)
文中詳細(xì)講了關(guān)于Java哈夫曼樹的概述以及用Java實現(xiàn)的方法,對各位正在學(xué)習(xí)java數(shù)據(jù)結(jié)構(gòu)的小伙伴們有很大的幫助喲,需要的朋友可以參考下2021-05-05
簡單了解java中靜態(tài)初始化塊的執(zhí)行順序
這篇文章主要介紹了簡單了解java中靜態(tài)初始化塊的執(zhí)行順序,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10
java Apache poi 對word doc文件進(jìn)行讀寫操作
這篇文章主要介紹了Apache poi 對word doc文件進(jìn)行讀寫操作的相關(guān)資料,需要的朋友可以參考下2017-01-01
SpringBoot應(yīng)用中出現(xiàn)的Full GC問題的場景與解決
這篇文章主要為大家詳細(xì)介紹了SpringBoot應(yīng)用中出現(xiàn)的Full GC問題的場景與解決方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-04-04
SpringBoot Pom文件依賴及Starter啟動器詳細(xì)介紹
這篇文章主要介紹了SpringBoot Pom文件的依賴與starter啟動器的作用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-09-09
Java實現(xiàn)EasyCaptcha圖形驗證碼的具體使用
Java圖形驗證碼,支持gif、中文、算術(shù)等類型,可用于Java Web、JavaSE等項目,下面就跟隨小編一起來了解一下2021-08-08
關(guān)于使用MyBatis簡化JDBC開發(fā)和解決SQL語句警告的問題
這篇文章主要介紹了關(guān)于使用MyBatis簡化JDBC開發(fā)和解決SQL語句警告的問題,如果idea和數(shù)據(jù)庫沒有建立鏈接,idea不識別表的信息,就會出現(xiàn)SQL語句的警告,需要的朋友可以參考下2023-05-05

