應用場景
- 已知有一個字符串
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;
}
}
代碼寫完,技術有限,僅供參考,歡迎各位大神指點!!!!