字符串匹配KMP算法實現

應用場景

  1. 已知有一個字符串str1 = "BBCABCDABABCDABCDBDE"和另外一個字符串str2 = "ABCDABD"
  2. 現在需要你來判斷str1是否包含str2,如果包含返回一個true,不存在返回一個false

解決辦法

  1. 暴力匹配法
  2. KMP算法匹配
暴力匹配法

在遇到這種匹配問題,我們一般想到的都是這種暴力匹配法,下面簡單講解一下他的實現方法。

暴力匹配法

  1. 創建兩個變量i,j並且分別賦值爲0,i爲指向str1的索引,j爲指向str2的索引
  2. 當我們str1.charAt(i) == str2.charAt(j)時即爲匹配成功,並i++,j++,匹配下一個位置的字符
  3. 如果我們str1.charAt(i) != str2.charAt(j)時,i回溯到本次匹配第一個元素成功位置的後一位即i = i - j + 1,並將j賦值爲0;
  4. 當我們有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算法
  1. KMP是一個解決模式串在文本串中是否出現過,如果出現過則找出最早出現的位置的經典算法。
  2. Knuth-Morris-Pratt字符串查找算法,簡稱爲"KMP"算法
  3. KMP算法就是利用之前已經判斷過信息,通過next數組,保存模式串中前後最長公共子序列的長度,每次回溯時,通過next數組找到,前面匹配過的位置,從而減少大量時間。
圖解算法

在這裏插入圖片描述

  1. 第一步用str1的第一個字符去比較str2的第一個字符,發現不符合,將str2後移一位。
    在這裏插入圖片描述
  2. 發現還是不符合,再次後移,直至找到匹配位置
    在這裏插入圖片描述
  3. 按照之前的原則向下匹配,匹配符合,繼續匹配str2第二個字符
    在這裏插入圖片描述
  4. 第二個字符也是符合,繼續相同的步驟
    在這裏插入圖片描述
  5. 直至遇到一個不相匹配的字符,這個時候按照我們的暴力匹配方法,下一次回溯的位置應該是第三步B所在的位置,然而這種方式是非常不明智的,因爲我們的BCD已經比較過了,沒必要進行重複的工作。KMP的基本想法就是想辦法把已經匹配過的字符去掉。
    在這裏插入圖片描述
  6. 如何才能將已經匹配過的值給他去除呢?這裏需要我們計算出一個部分匹配表
    在這裏插入圖片描述
  7. 已知空格與D不相互匹配,但是前面的ABCDAB是匹配的,查表得知,最後一個匹配字符B對應的部分匹配表爲2,因此按照下面公式得知向後移動的次數:移動位數 = 已匹配數 - 對應部分匹配值
    得知 4 = 6 - 2
    在這裏插入圖片描述
  8. 因爲C與空格不匹配,這時部分匹配爲"AB",得到他的部分匹配值爲0,所以需要移動2位
    在這裏插入圖片描述
  9. 發現C與空格不相匹配,則向後移動一位在這裏插入圖片描述
  10. 一個字符一字符比較發現C與D不匹配,計算出需要移動4位
    在這裏插入圖片描述
  11. 最後發現全部匹配成功,程序結束
部分匹配表

首先講解一下前綴與後綴
字符: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;
	}
}

代碼寫完,技術有限,僅供參考,歡迎各位大神指點!!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章