TMD ,KMP!

以爲搞清楚了BM算法的思想,就容易理解KMP了,shit!還是很難理解關於KMP算法中next數組是如何高效獲得的,既然如此暫時不追究了,不過已然不妨礙把代碼搞清楚!
跟BM算法類似,KMP算法中主串和模式串的比對也有類似的東西如:壞字符和好前綴。
沒錯,就是好前綴,BM算法中是好後綴,KMP算法中是好前綴!
在這裏插入圖片描述
當遇到壞字符的時候,模式串依然是需要往後移動,對於KMP算法來說依然是設法一次滑動多個位置,而不是一個字符一個字符去地低效地比較。
其實就是在好前綴本身的後綴子串中,查找最長的能跟好前綴的前綴子串匹配的串。
在這裏插入圖片描述
把好前綴的所有後綴子串中,最長的可匹配前綴子串的那個後綴子串叫做最長可匹配後綴子串;對應的前綴子串叫做最長可匹配前綴子串
在這裏插入圖片描述
如何求解好前綴的最長可匹配前綴子串和後綴子串?這個問題其實只跟模式串本身有關係,既然是好前綴,那麼模式串中也一定包含好前綴,那麼問題就轉化爲:求模式串好前綴的最長可匹配前綴子串。
在KMP算法中可以事先根據模式串本身來構建一個存儲最長可匹配前綴子串的數組,這個數組的下標爲模式串前綴結尾字符的下標(也就是好前綴的候選字符串),值爲這個前綴的最長可匹配前綴子串的結尾字符下標。如:
在這裏插入圖片描述
這個next數組我們稱之爲“失效函數”,失效函數如何計算出來,一個簡單的方法是:如圖想求出前綴b[0,4]即ababa這個前綴的最長可匹配前綴的結尾字符下標,可以把b[0,4]的後綴子串全部列舉出來跟b[0,4]的前綴去匹配,這樣就可以得到最長的可匹配前綴的結尾字符,如圖就是ababa的最長前綴子串是aba,結尾字符下標就是2,於是next[4]=2.
在這裏插入圖片描述
但是這種方式求next數組的值看起來比較低效,高效的方法有,極客時間爭哥的課程第34節裏有,可惜我沒看懂!感覺變量太多了,我是看得繞進去了,感興趣可以自己去看下,爭哥的教程很棒!
下邊我就假設next數組已經是被填充的,直接把代碼拿上來看看:

package com.study.algorithm;

/**
 * KMP算法
 * @author jeffSheng
 * @date 20191001
 *
 */
public class Kmp {
	public static void main(String[] args) {
		String a = "ababaeabac"+"ababacd"+"xxxx";
		String b = "ababacd";
		int x = kmp(a.toCharArray(),a.length(),b.toCharArray(),b.length());
		System.out.println(x);
	}

	// a, b 分別是主串和模式串;n, m 分別是主串和模式串的長度。
	public static int kmp(char[] a, int n, char[] b, int m) {
	  int[] next = getNexts(b, m);
	  int j = 0;
	  for (int i = 0; i < n; ++i) {
	    while (j > 0 && a[i] != b[j]) { // 一直找到 a[i] 和 b[j]
	      j = next[j - 1] + 1;
	    }
	    if (a[i] == b[j]) {
	      ++j;
	    }
	    if (j == m) { // 找到匹配模式串的了
	      return i - m + 1;
	    }
	  }
	  return -1;
	}
	
	
	// b 表示模式串,m 表示模式串的長度
	private static int[] getNexts(char[] b, int m) {
	  int[] next = new int[m];
	  next[0] = -1;
	  int k = -1;
	  for (int i = 1; i < m; ++i) {
	    while (k != -1 && b[k + 1] != b[i]) {
	      k = next[k];
	    }
	    if (b[k + 1] == b[i]) {
	      ++k;
	    }
	    next[i] = k;
	  }
	  return next;
	}
	


}

代碼我試過了,正常得出結果,對於kmp這個方法可以做如下圖解:
在這裏插入圖片描述
雖然沒有搞清楚next數組的高效計算方式,但是理解了整體的思想,我覺得也是夠了,能夠在實際軟件開發中用得上也就可以了,我不覺得非要把那些細節搞清楚!TMD!KMP!

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