日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

模式匹配算法----KMP算法以及next数组的解法

發布時間:2025/3/15 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 模式匹配算法----KMP算法以及next数组的解法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

KMP算法:求字符串匹配(也叫模式匹配)的算法,即給定一個字符串,求其某一子串在其中出現的位置。

普通模式匹配

例如:給定字符串為abcabaaabaabcac,求其子串abaabcac在其中出現的位置。

結果為7

對于這種問題,沒有經驗的編程者通常會采用逐個匹配的方法,來得出結果。這就是最簡單一種算法思想。

1. 逐個進行比較,如果相同,就繼續比較下一個,但是我們可以看到下圖中,c與a不相同,這就是所謂的“失配”。

2. 當發生失配,我們會將子字符串逐個后移,直到新的匹配建立,再逐個比較

3.

4.

5.

6.

7.

根據上面的方法,我們可以看到第二步有兩個圖,這是為什么呢?這是因為當出現失配時候,字符串每次后移一個的方法,不能夠立刻建立匹配,還需要繼續后移才能建立。也就是說,這種情況下,后移兩個才能建立匹配。

當然這個例子比較小,只出現了兩次這種情況,但是如果是較大的數據,這種冗余操作是十分低效的。這也就是KMP算法優化的地方。

KMP算法--next[]

KMP算法會創建一個next[]數組,用來保存一個字符失配后,到底跳轉到第幾個的位置才能更快速的建立匹配。這里用了跳轉這個詞,因為并不是向后移動next[i]位,而應該是直接跳轉到相應的位置,使失配位與第next[i]位相對。這個數組是KMP算法的核心。

下面以字符串abaabcac為例,求解next數組,模式匹配的數組下標從1開始(這個算法推薦這么做,很多事情沒有那么多理由)

?

next數組按照最長相等前后綴長度求解:

next[1],字符串“a”,前綴{},后綴{},沒有相等前后綴,next記為0。要注意,前后綴均不包括整個串。

next[2],字符串“ab”,前綴{a},后綴{b},沒有相等前后綴,next記為0。

next[3],字符串“aba”,前綴{a,ab},后綴{a,ba},相等前后綴{a},長度為1,next記為1。

next[4],字符串“abaa”,前綴{a,ab,aba},后綴{a,aa,baa},相等前后綴{a},長度為1,next記為1。

next[5],字符串“abaab”,前綴{a,ab,aba,abaa},后綴{b,ab,aab,baab},相等前后綴{ab},長度為2,next記為2。

next[6],字符串“abaabc”,前綴{a,ab,aba,abaa,abaab},后綴{c,bc,abc,aabc,baabc},相等前后綴{},next記為0。

next[7],字符串“abaabca”,前綴{a,ab,aba,abaa,abaab,abaabc},后綴{a,ca,bca,abca,aabca,baabca},相等前后綴{a},長度為1,next記為1。

next[8],字符串“abaabcac”,前綴{a,ab,aba,abaa,abaab,abaabc,abaabca},后綴{c,ac,cac,bcac,abcac,aabcac,baabcac},相等前后綴{},next記為0。

i12345678
str.charAt(i)abaabcac
next[i]00112010

由于使用next[]時,每次失配,都需要找它前面一個元素的next[]進行移動,為了方便,我們將next數組右移一位。最左側填充-1,舍棄最右側的元素。

i12345678
str.charAt(i)abaabcac
next[i]-10011201

為了簡化計算,我們對next[]整體+1,這里得到的是我們通常使用的next[]。

i12345678
str.charAt(i)abaabcac
next[i]01122312

?

求解next數組代碼:

private static int[] get_Next(String str){ int[] next = new int[str.length()+1]; int j = next[2];// 這里next[1]和next[2]直接賦值next[1] = 0;next[2] = 1;for(int i = 2; i < str.length(); i++) { while(j > 0 && str.charAt(i-1) != str.charAt(j)) {j = next[j]; }if(str.charAt(i-1) == str.charAt(j)) {j++;}next[i] = j;} return next; }

KMP算法改進--nextval[]

比較當前next[i]的值,與

1.前兩位必為0,1

計算nextval[3]時,我們可以知道第三位字符位‘a’,next[3]=1,故查看第1位的字符為‘a’,字符相同,所以nextval[3]=next[1]=0

計算nextval[4]時,我們可以知道第四位字符位‘a’,next[4]=2,故查看第2位的字符為‘b’,字符不同,所以nextval[4]=next[4]=2

計算nextval[5]時,我們可以知道第五位字符位‘b’,next[5]=2,故查看第2位的字符為‘b’,字符相同,我們知道next[2]=1,故繼續查看第1位的字符為‘a’,字符不同,所以nextval[5]=next[2]=1

計算nextval[6]時,我們可以知道第六位字符位‘c’,next[6]=3,故查看第3位的字符為‘a’,字符不同,所以nextval[6]=next[6]=3

計算nextval[7]時,我們可以知道第七位字符位‘a’,next[7]=1,故查看第1位的字符為‘a’,字符相同,所以nextval[7]=next[1]=0

計算nextval[8]時,我們可以知道第八位字符位‘c’,next[8]=2,故查看第2位的字符為‘b’,字符不同,所以nextval[7]=next[7]=2

i12345678
str.charAt(i)abaabcac
nextval[i]01021302

根據next數組,我們再來做一遍這個題目:給定字符串為abcabaaabaabcac,求其子串abaabcac在其中出現的位置。

?

1.創建匹配,第4個字符發生失配

2.使失配位與子串的第next[4]=2位相對,但是這是第二個字符又失配了

3.使失配位與子串的第next[2]=1位相對,此時第一個字符就失配

4.使失配位與子串的第next[1]=0位相對,注意我們的next數組是從1開始算的,所以相當于整體后移一個單位,下圖的失配位實際是"c"

5.使失配位與子串的第next[4]=2位相對

6.使失配位與子串的第next[4]=2位相對

7.匹配成功

完整代碼如下:

public class Main { public static void main(String[] args) { String str = "abaabcac"; String orig ="aabaabcac"; int[] next = get_Next(str); for (int i = 1; i < next.length; i++) {System.out.print(next[i] + " ");}System.out.println();search(orig, str, next); } //next[i]表示的是str的"部分匹配表",這個表表示的是str前綴與后綴的最長公共字符串的長度private static int[] get_Next(String str){ int[] next = new int[str.length()+1]; int j = next[2];// 這里next[1]和next[2]直接賦值next[1] = 0;next[2] = 1;// 第2位之后的next,為什么從2開始,不是已經賦值了嗎?這在于str.charAt(0)為字符串的第一個字母for(int i = 2; i < str.length(); i++) { while(j > 0 && str.charAt(i-1) != str.charAt(j)) {j = next[j]; }if(str.charAt(i-1) == str.charAt(j)) {j++;}next[i] = j;} return next; } //orig為主串,而find為模式串,查找匹配位置以及匹配長度 private static void search(String orig, String find, int[]next){ int j = next[0]; for(int i = 0;i < orig.length(); i++){ while(j > 0 && orig.charAt(i) != find.charAt(j)) j = next[j]; if(orig.charAt(i) == find.charAt(j)){ j++; }if(j == find.length()){ System.out.println("find at position " + (i - j+1)); System.out.println(orig.subSequence(i - j + 1, i + 1)); j = next[j];}}} }

當然還有一種BM算法效率比KMP算法還好。有興趣的讀者可以參考時空權衡在模式匹配算法中的應用(JAVA)--Horspool算法(簡化版BM算法)

nextval數組實際的數值是明顯要小于next數組的,nextval數組由于考慮到了移動到的位置的數與當前位置數的關系,可以減少移動的距離。

?

?

總結

以上是生活随笔為你收集整理的模式匹配算法----KMP算法以及next数组的解法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。