应用场景
- 已知有一个字符串
str1 = "BBCABCDABABCDABCDBDE"
和另外一个字符串str2 = "ABCDABD"
- 现在需要你来判断
str1
是否包含str2
,如果包含返回一个true
,不存在返回一个false
解决办法
- 暴力匹配法
- KMP算法匹配
暴力匹配法
在遇到这种匹配问题,我们一般想到的都是这种暴力匹配法,下面简单讲解一下他的实现方法。
- 创建两个变量i,j并且分别赋值为0,i为指向str1的索引,j为指向str2的索引
- 当我们
str1.charAt(i) == str2.charAt(j)
时即为匹配成功,并i++,j++,匹配下一个位置的字符 - 如果我们
str1.charAt(i) != str2.charAt(j)
时,i回溯到本次匹配第一个元素成功位置的后一位即i = i - j + 1
,并将j赋值为0; - 当我们有j的大小等于str2的长度时,即为匹配成功退出循环
暴力匹配代码实现
public static boolean violenceMatch(String str1, String str2) {
int i = 0;
int j = 0;
while (i < str1.length() && j < str2.length()) {
if (str1.charAt(i) == str2.charAt(j)) {
i++;
j++;
} else {
i = i - j + 1;
j = 0;
}
}
if (j == str2.length()) {
return true;
} else {
return false;
}
}
存在的问题
这种算法中存在大量的回溯,降低了效率,有些已经匹配过的字符也被匹配了。所以我们使用下面的KMP
算法。
KMP算法
- KMP是一个解决模式串在文本串中是否出现过,如果出现过则找出最早出现的位置的经典算法。
- Knuth-Morris-Pratt字符串查找算法,简称为"KMP"算法
- KMP算法就是利用之前已经判断过信息,通过next数组,保存模式串中前后最长公共子序列的长度,每次回溯时,通过next数组找到,前面匹配过的位置,从而减少大量时间。
图解算法
- 第一步用str1的第一个字符去比较str2的第一个字符,发现不符合,将str2后移一位。
- 发现还是不符合,再次后移,直至找到匹配位置
- 按照之前的原则向下匹配,匹配符合,继续匹配str2第二个字符
- 第二个字符也是符合,继续相同的步骤
- 直至遇到一个不相匹配的字符,这个时候按照我们的暴力匹配方法,下一次回溯的位置应该是第三步B所在的位置,然而这种方式是非常不明智的,因为我们的BCD已经比较过了,没必要进行重复的工作。KMP的基本想法就是想办法把已经匹配过的字符去掉。
- 如何才能将已经匹配过的值给他去除呢?这里需要我们计算出一个部分匹配表
- 已知空格与D不相互匹配,但是前面的ABCDAB是匹配的,查表得知,最后一个匹配字符B对应的部分匹配表为2,因此按照下面公式得知向后移动的次数:移动位数 = 已匹配数 - 对应部分匹配值
得知 4 = 6 - 2
- 因为C与空格不匹配,这时部分匹配为"AB",得到他的部分匹配值为0,所以需要移动2位
- 发现C与空格不相匹配,则向后移动一位
- 一个字符一字符比较发现C与D不匹配,计算出需要移动4位
- 最后发现全部匹配成功,程序结束
部分匹配表
首先讲解一下前缀与后缀
字符:bread
前缀: b, br, bre,brea
后缀: read, ead, ad, d
部分匹配值的产生就是找出前缀和后缀公共字符的长度
KMP算法代码实现
public boolean kmp(String str1, String str1, 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 == str1.length()) {
return true;
} else {
return false;
}
}
public int[] getNext(String str) {
int[] next = new int[str.length()];
next[0] = 0;
for(int i = 1,j = 0;i < str.length();i++) {
while (j > 0 && str.charAt(i) != str.charAt(j)) {
j = next[j - 1];
}
if (str.charAt(i) == str.charAt(j)) {
j = j + 1;
}
next[i] = j;
}
}
代码写完,技术有限,仅供参考,欢迎各位大神指点!!!!