1. 程式人生 > >KMP優化字串

KMP優化字串

bsp 復雜 arc 多說 return 不解釋 提前 簡便 優化

1.背景:KMP是由3個外國人想出來的設計的線性時間字符串匹配算法。時間復雜度很低O(n),是判定字串的一個十分簡便的方法。

2.運算步驟:假定1個字符串A,對字符串A匹配A的子串,求出一個數組next,通過預算減少了運算的時間,其中next[i]表示了A中以i結尾的的非前綴字串,非前綴字串很好理解的,就比如bread的前綴字串有b,br,bre,brea;(如果字符串A為a,那麽A的字串為空)然後將以i為結尾的非前綴字串與A的前綴能匹配的最大長度,就是next[i]=max{j},其中i<j且A[i-j+1~j]=A[1~j];然後對A與B2個字符串相匹配,求出數組f,其中f[i]表示B中以i結尾的字串與A的前綴能夠匹配的最大長度,就是f[i]=max{j},其中j≤i且B[i-j+1~i]=A[1~j];這樣對字串進行優化。

3.KMP是如何提高計算的速度的?

這個十分容易理解,比如給一個字符串A,裏面是abcabcabccc,用另一個串B去比較,假設B為abcabcc,如果按照原始枚舉算法,就要從第一個字符開始比較到最後一個字符,這種時間復雜度就是很麻煩的,但是如果提前記錄A的子串,再尋找B與A子串相同的部分,就可以極大的減少時間,設想一下,給你一個abcabcabc……循環的好長好長字符串,再給你一個abcd,這樣你就會發現,用枚舉的方法,這個超級無比慢,但是你用KMP算,發現abc相同,你只需要移動3個位置,便可以從這個超級超級長的字符串中尋找你需要的東西,然後發現沒有輸出0,這個例子就很好的說明了KMP的效率極其之高。

4.next數組的求法:

①理論:初始化next[1]=j=0,假定next[1~i -1]已經求出,那麽便可以求出next[i]。然後繼續擴展next的長度,如果擴展到下個字符不同的時候,令此時的j變為next[j],直到j為0重新匹配。如果可以擴展成功,令j++,next[i]的值就是j。

②代碼:

 1 int KMP_search(char* s, char* p)  
 2 {  
 3     int i = 0;  
 4     int j = 0;  
 5     int sLen = strlen(s);  //定義長度 
 6     int pLen = strlen(p);  //
定義長度 7 while (i < sLen && j < pLen) 8 { 9 10 if (j == -1 || s[i] == p[j]) 11 { 12 i++; 13 j++; 14 } //①如果j = -1,也可以說字串的匹配成功,那麽就讓i++,j++ 15 else 16 { 17 j = next[j]; 18 } 19 } //②如果j != -1,並且當前字符匹配失敗(即S[i] != P[j]),則令 i 不變,j = next[j],就是我前面進行了很簡單的解釋 20 //next[j]即為j所對應的next值 21 if (j == pLen) 22 return i - j; //這個返回值非常樸素,基本都能看懂我就不解釋了 23 else 24 return -1; 25 }

5.f函數的求法:

①理論:和next數組的求法是一樣的,代碼也差不多,所以就不做多的廢話了。

6.遞歸求next數組:

(我認為這個方式學過遞歸和字符串的人都比較容易理解,理論呢就不多說了,和next求法是一樣的,遞歸的方式可以去看遞歸,所以我話不多說直接代碼)

 1 void howtofindnext(char* p, int next[])  
 2 {  
 3     int pLen = strlen(p);//同樣是對長度進行定義  
 4     next[0] = -1; 
 5     int k = -1;   
 6     int j = 0;  
 7     while (j < pLen - 1)//如果j的大小小於了子串的長度,那麽執行循環,大了怎麽可能是字串嘞  
 8     {  
 9         //p[k]表示前綴,p[j]表示後綴,前後綴我前面已經有所解釋了 
10         if (k == -1 || p[j] == p[k])  
11         {  
12             ++j;  
13             ++k;  
14             //較之前next數組求法,改動在下面4行,這十分重要的!!!!! 
15             if (p[j] != p[k])  //前綴與後綴不同 
16                 next[j] = k;  
17             else  
18                 //因為不能出現p[j] = p[next[j]],所以當出現時需要繼續遞歸,k = next[k] = next[next[k]]  
19                 next[j] = next[k];  //進行下一次遞歸 
20         }  
21         else  
22         {  
23             k = next[k];  //這個遞歸方式較上次的next比較容易寫,但是我個人認為,上種方法比較容易理解和掌握 
24         }  
25     }  
26 }  

就是這樣結束了,我覺得新手也可以看的懂哦!!!

KMP優化字串