字符串匹配问题:
先看一下暴力匹配法(不是KMP算法,用暴力匹配和KMP算法做对比)
如果用暴力匹配的思路,并假设现在 str1 匹配到 i 位置,子串 str2 匹配到 j 位置,则有:
/** * @author zk * @version 1.0.0 * @ClassName ViolenceMatch.java * @Description TODO 暴力匹配算法(不是kmp算法) * @createTime 2021年09月30日 10:26:00 */ public class ViolenceMatch { public static void main(String[] args) { String s1 = "迪丽热巴 迪丽热巴你你好 迪丽迪丽热巴迪丽热巴你好"; String s2 = "迪丽热巴你好"; int i = violenceMatch(s1, s2); System.out.println(i); } // 暴力匹配算法的实现 public static int violenceMatch(String str1, String str2) { char[] s1 = str1.toCharArray(); char[] s2 = str2.toCharArray(); // 索引 int i = 0; int j = 0; while (i < s1.length && j < s2.length) { if (s1[i] == s2[j]) { i++; j++; } else { i = i - j + 1; j = 0; } } if (j >= s2.length) { return i - j; } else { return -1; } } }
字符串匹配问题:
思路分析图解:
举例来说,有一个字符串 Str1 = “BBC ABCDAB ABCDABCDABDE”,判断,里面是否包含另一个字符串 Str2 = “ABCDABD”?
“部分匹配值”就是”前缀”和”后缀”的最长的共有元素的长度。以”ABCDABD”为例,
”A”的前缀和后缀都为空集,共有元素的长度为 0;
”AB”的前缀为[A],后缀为[B],共有元素的长度为 0;
”ABC”的前缀为[A, AB],后缀为[BC, C],共有元素的长度 0;
”ABCD”的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为 0;
”ABCDA”的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为”A”,长度为 1;
”ABCDAB”的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为”AB”,长度为 2;
”ABCDABD”的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为 0。
import java.util.Arrays; /** * @author zk * @version 1.0.0 * @ClassName KMPAlgorithm.java * @Description TODO * @createTime 2021年09月30日 11:46:00 */ public class KMPAlgorithm { public static void main(String[] args) { String str1 = "BBC ABCDAB ABCDABCDABDE"; String str2 = "ABCDABD"; int[] next = kmpNext(str2); System.out.println(Arrays.toString(next)); int index = kmpSearch(str1, str2, next); System.out.println(index); } //写出我们的 kmp 搜索算法 /** * @param str1 源字符串 * @param str2 子串 * @param next 部分匹配表, 是子串对应的部分匹配表 * @return 如果是-1 就是没有匹配到,否则返回第一个匹配的位置 */ public static int kmpSearch(String str1, String str2, int[] next) { for (int i = 0, j = 0; i < str1.length(); i++) { while (j > 0 && str1.charAt(i) != str2.charAt(j)) { j = next[j - 1]; } if (str1.charAt(i) == str2.charAt(j)) { j++; } if (j == str2.length()) { return i - j + 1; } } return -1; } //获取到一个字符串(子串) 的部分匹配值表 public static int[] kmpNext(String dest) { //创建一个 next 数组保存部分匹配值 int[] next = new int[dest.length()]; next[0] = 0; for (int i = 1, j = 0; i < dest.length(); i++) { while (j > 0 && dest.charAt(i) != dest.charAt(j)) { j = next[j - 1]; } if (dest.charAt(i) == dest.charAt(j)) { j++; } next[i] = j; } return next; } }