KMP算法詳解與實現和next數組的代碼化總結----看過的人都理解了!!

KMP2年前反覆看的時候,對next數組和基本原理,記一遍忘一遍,最近要用到字符串匹配得問題,要造輪子的時候又想到它了,這次好好整理一遍,要再次深刻的理解一遍。

KMP–簡介

kmp是由Knuth-Morris-Pratt三位發明者共同命名的

傳統匹配

EFEFEVDDCSAFFFEFERFTEWV
當我們想讓FEFER這個pattern字符串去匹配上面的text字符串時,我們通常的做法是嘗試是回朔算法。
PS: 回溯算法是一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就“回溯”返回。
第一步:匹配不正確在下一個字符重新開始
在這裏插入圖片描述
第二步:匹配成功繼續對FEFER這個pattern字符串進行後續的驗證
在這裏插入圖片描述
第三步:直到我們發現最後一個字符不一致,此次從第二個字符開始匹配的方式失敗,
在這裏插入圖片描述
第四步:回朔,從第三個字符重新開始,失敗,繼續對第四個字符重新開始匹配,直至匹配成功。
在這裏插入圖片描述
這樣的方式不難猜出,當被匹配的text字符串長度爲N,匹配得pattern字符串長度爲M,那麼時間複雜度達到O(N*M)

KMP優化

EFEFEVDDCSAFFFEFERFTEWV
同樣當我們想讓FEFER這個字符串去匹配上面的字符串時,我們這次嘗試的算法爲KMP算法。
第一步:匹配不正確在下一個字符重新開始
在這裏插入圖片描述
第二步:匹配成功繼續對FEFER字符串進行後續的驗證
在這裏插入圖片描述
第三步:直到我們發現最後一個字符不一致,從這裏開始發生改變,我們無需回到第二個字符開始
在這裏插入圖片描述
提取FEFE這個已匹配字符數
我們去尋找這個FEFER他的子串的前後綴最大公共子串

  • F的前後綴子串都爲空,相同子串爲0
  • FE的前後綴子串分別爲{F} | {E},最大相同子串爲0
  • FEF的前後綴子串分別爲{F},{FE} | {F},{EF},最大相同子串長度爲1
  • FEFE的前後綴子串分別爲{F},{FE},{FEF} | {E},{FE},{EFE},最大相同子串長度爲2
  • FEFER的前後綴子串分別爲{F},{FE},{FEF},{FEFE} | {R},{ER},{FER},{EFER},最大相同子串長度爲0

計算下次應該在哪個位置重新開始匹配
移動距離=已匹配成功字符長度-最大相同子串長度
第四步:我們經過計算需要移動2=4-2個單位,所以我們直接從第四個字符開始匹配,省去了一些匹配次數
在這裏插入圖片描述
在這裏插入圖片描述

第五步:同理我們經過計算需要移動2=2-0個單位,所以我們直接從第6個字符開始匹配,省去了一些匹配次數,反覆如此,直到匹配成功
提取FE這個已匹配字符數

  • F的前後綴子串都爲空,相同子串爲0
  • FE的前後綴子串分別爲{F} | {E},最大相同子串爲0
    在這裏插入圖片描述
    這樣的方式不難猜出,當被匹配的字符串pattern長度爲N,匹配得字符串長度爲M,那麼時間複雜度達到O(N+M),當然如果沒有出現類似這種匹配字串的重複現象,他又會退回成回朔算法。

next數組的求法

我們應用到編程中,最難實現的點是如何根據待匹配的pattern字符串求出對應每一位的最大相同前後綴的長度
在程序中,我們可以將其轉化爲對next數組的求解
next數組next[k]本質是對pattern字符串的子串長度爲k+1時最大相同前後綴子串長度
例如abab:如果列出它最大前後綴子串長度表(此處所說子串不包含本身字符串)

k=0 | a k=1 | ab k=2 | aba k=3 | abab
前綴子串(s[0~k]) 空集 {a} {a}{ab} {a}{ab}{aba}
後綴子串(s[(3-k)~3]) 空集 {b} {a}{ba} {a}{ab}{bab}
相同前後綴子串長度 0` 0 1 2
next[0] next[1] next[2] next[3]
next數組 -1 -1 0 [a的下標] 1 [b的下標]

由此可以得出:
next[k]是s[0~k]字符串的最長相等前後綴的前綴最後一位的下標
以此來更好的將其代碼化:
瞭解到這裏我們將抽象的語言已經轉化爲代碼的語言,接下來實現的方式我們選擇遞推,通過已知的next[0]~next[k-1]來推出next[k]

public void getNext(char s[], int len){
	int j = -1;
	next[0] = -1;
	for(int i = 1; i < len; i++){
		while(j != -1 && s[i] != s[j + 1]){
			j = next[j];
		}
		if(s[i] == s[j + 1]){
			j++;
		}
		next[i] = j;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章