內容:
1、問題引入
2、暴力求解方法
3、優化方法
4、kmp演算法
1、問題引入
原始問題:
對於乙個字串 str (長度為n)和另乙個字串 match (長度為m),如果 match 是 str 的子串,
請返回其在 str 第一次出現時的首字母下標,若 match 不是 str 的子串則返回 -1
注:
子串行和子串的區別:子串行可以不連續,子串必須連續
2、暴力求解方法
暴力求解方法:將 str 從頭開始遍歷並與 match 逐次比較,若碰到了不匹配字母則終止此次遍歷轉而從 str 的 第二個字元開始遍歷
並與 match 逐次比較,直到某一次的遍歷每個字元都與 match 匹配否則返回 -1 。易知此種 做法的時間複雜度為 o(n*m)
注:kmp演算法則給出求解該問題時間複雜度控制在 o(n) 的解法
3、優化方法
優化方法:借助next陣列進行優化
在乙個字串中,每個字元之前的最長字首和最長字尾的最大匹配長度就是next陣列中的值,next陣列在kmp演算法中的目的就是決定下次匹配物件
注:字首不能包含最後乙個字元,字尾也不能包含第乙個字元(字首和字尾不能是字串整體!)
next陣列示例:
如何求next陣列:
當串 match 長度 mlen=1 時,規定 next[0]=-1 。當 mlen=2 時,去掉 match[1] 之後只剩下 match[0] ,
大匹配子串長度為0(因為字首子串不能包含串尾字元,字尾子串不能包含串首字元),即 next[1]=0
而當 mlen>2 時, next[n] (n>=2)都可以推算出來:
如上圖所示,如果我們知道了next[n-1] ,那麼 next[n] 的求解有兩種情況:如果 match[cn]=match[n-1] ,
那麼由a區域與b區域(a、b為最大匹配字首子串和字尾字串)相同可知 next[n]=next[n1]+1 ;
如果 match[cn]!=match[n-1] ,那麼求a區域中下乙個能和b區域字尾子串中匹配的較大的乙個,
即a區域 的大匹配字首字串 c區域 ,將 match[n-1] 和c區域的後乙個位置( cn' )上的字元比較,
如果相等則 next[n] 等於c區域的長度+1,而c區域的長度就是 next[cn] ( next陣列的定義如此);
如果不等則將 cn 打 到 cn' 的位置繼續和 match[n-1] 比較,直到 cn 被打到 0 為止(即next[cn]=-1 為止),那麼此時next[n]=0
求next陣列**:
14、kmp演算法kmp演算法的原理如下:子串 match 的 next陣列找到之後就可以進行 kmp 演算法求解此問題了。 kmp 演算法的邏輯是對於 str 的 i~(i+k) 部分 ( i 、 i+k 合法)public
static
int getnextarray(char
str) ;4}
5int next = new
int[str.length];
6 next[0] = -1;
7 next[1] = 0;
8int i = 2;
9int cn = 0;
10while (i
if (cn > 0) else18}
19return
next;
20 }
和 match 的 0~k 部分( k合法),如果有 str[i]=match[0] 、 str[i+1]=match[1] …… str[i+k-1]=match[k-1] ,但 str[i+k]!=[k] ,
那麼 str 的 下標不用從i+k 變為 i+1 重新比較,只需將子串 str[0]~str[i+k-1] 的大匹配字首子串的後乙個字元 cn 重新與 str[i+k] 向後依次比較,
後面如果又遇到了不匹配的字元重複此操作即可:
當遇到不匹配字元時,常規的做法是將 str 的遍歷下標 sindex 移到 i+1 的位置並將 match 的遍歷下標 mindex 移到 0 再依次比較,
而 kmp 演算法則不是這樣,當遇到不匹配的字元str[i+k] 和 match[k] 時, str 的遍歷指標 sindex=i+k 不用動,
將 match 右滑並將其遍歷指標 mindex 打到子串 match[0]~match[k-1]的最大匹配字首子串的後乙個下標 n 的位 置。
然後 sindex 從 i+k 開始, mindex 從 n 開始,依次向後比較,若再遇到不匹配的數則重複此過程
kmp演算法核心**:
1可以發現 kmp 演算法中 str 的遍歷指標並沒有回溯這個動作(只向後移動),當完成匹配時 sindex 的移動次數小 於 n ,public
static
intgetindexof(string s, string m)
5char str1 =s.tochararray();
6char str2 =m.tochararray();
7int i1 = 0;
8int i2 = 0;
9int next =getnextarray(str2);
10while (i1 < str1.length && i2
if (next[i2] == -1) else19}
20return i2 == str2.length ? i1 - i2 : -1;
21 }
否則 sindex 移動到串尾也會終止迴圈,所以 while 對應的匹配過程的時間複雜度為 o(n) ( if(next[j] != -1) 的
執行次數只會是常數次,因此可以忽略)
完整的kmp**及測試樣例如下:
1//kmp演算法
2public
class
kmp
7char str1 =s.tochararray();
8char str2 =m.tochararray();
9int i1 = 0;
10int i2 = 0;
11int next =getnextarray(str2);
12while (i1 < str1.length && i2
if (next[i2] == -1) else21}
22return i2 == str2.length ? i1 - i2 : -1;23}
2425
public
static
int getnextarray(char
str) ;28}
29int next = new
int[str.length];
30 next[0] = -1;
31 next[1] = 0;
32int i = 2;
33int cn = 0;
34while (i
if (cn > 0) else42}
43return
next;44}
4546
public
static
void
main(string args)
53 }
經典KMP演算法整理
kmp演算法 大名鼎鼎的演算法 kmp由三位前輩的名字縮寫組成 其中第一位就是寫the art of the computer programming的高德納 它是一種效率很高的字串匹配演算法 傳統樸素做法的時間複雜度為o n m 而kmp演算法能將時間複雜度縮小到o n m 下面進入正題 kmp演...
KMP演算法詳解
模式匹配的kmp演算法詳解 這種由d.e.knuth,j.h.morris和v.r.pratt同時發現的改進的模式匹配演算法簡稱為kmp演算法。大概學過資訊學的都知道,是個比較難理解的演算法,今天特把它搞個徹徹底底明明白白。注意到這是乙個改進的演算法,所以有必要把原來的模式匹配演算法拿出來,其實理解...
KMP演算法詳解
kmp演算法即knuth morris pratt演算法,是模式匹配的一種改進演算法,因為是名字中三人同時發現的,所以稱為kmp演算法。因為偶然接觸到有關kmp的問題,所以上網查了一下next陣列和 nextval陣列的求法,卻沒有找到,只有在csdn的資料檔案裡找到了next陣列的簡單求法 根據書...