字串匹配問題 KMP演算法

2021-08-17 10:31:45 字數 2483 閱讀 2171

字串匹配問題:給定兩個字串s(主串)和t(模式串),假設n=strlen(s) > strlen(t)=m,判斷主串s中是否包含模式t,且返回t在s中所在的起始位置。這裡為簡單起見,若s包含t,則只返回第乙個t所在的位置。

一般的蠻力法如下:

蠻力法在遇到不匹配時,j每次都要回到t的起點,從新開始匹配,這樣來看效率就比較低,蠻力法的時間複雜度是o(n*m)。

思想:盡量利用

已經部分匹配的結果資訊,盡量讓

i 不回溯,加快模式串t的滑動速度。

先舉個啟發性的例子,然後引出理論。例子:

在上一趟s和t匹配結果的基礎上,如果知道t本身的結構資訊,那麼第2、4、5趟的步驟其實是可以省略的,且i可以不用回溯(i不回溯待會兒再來直觀理解)。

1.1、模式串t中的資訊

抓住 部分匹配時的兩個特徵:

如上圖所示,假設s[i]和t[j]不相等後,從t的第k個位置開始和s中的第i個位置比較,那麼:

(1)從圖的後半部分可得:

(2)從圖的後前部分可得: 

所以,兩式聯立可得:

所以,由上面的推理可知,只要提前知道模式串t本身的結構資訊,就可以由j計算出k,即下一回t的匹配起點。另外,(3)式可能存在多種不同長度的首尾相等的可能,那麼在這樣的情況下,肯定是k越大越好,這樣一方面可以減少再次匹配的字元數量;另一方面,t向右移動的位置相當s而言也是最慢的,這樣也不會錯過各種匹配的情況。比如:

令k = next[ j ],則:

計算next[j]的方法:

由模式t的字首函式定義易知,next[1]=0,假設已經計算出next[1],next[2],…,next[j],如何計算next[j+1]呢?設k=next[j],則已有:

此時,比較tk和tj,可能出現兩種情況:

(1)tk=tj:說明t1 … tk-1 tk=tj-k+1 … tj-1 tj,由字首函式定義,next[j+1]=k+1;

(2)tk≠tj:此時要找出t1 … tj-1的字尾中第2大真字首,顯然,這個第2大的真字首就是next[next[j]]=next[k]。

再比較tnext[k]和

tj,此時仍會出現兩種情況,當

tnext[k]=tj時,與情況(1)類似,next[j]=next[k]+1;當

tnext[k]≠tj時,與情況(2)類似,再找t1 … tj-1的字尾中第3大真字首。重複執行上述步驟,直到找到t1 … tj-1的字尾中的最大真字首,或確定t1 … tj-1的字尾中不存在真字首,此時,next[j+1]=1。

求next陣列**:

void getnext(char t, int next)

else

k = next[k]; //往前找

}}

kmp中的核心就是求next陣列,之後就沒什麼關鍵的了。kmp的時間複雜度為o(n+m),當n>>m時,時間複雜度是o(n)。完整**如下:

int callen(char *p)     //計算字元陣列長度

return count;

}void getnext(char t, int next)

else

k = next[k]; //往前找 }}

#includeusing namespace std;

#define str_len 52

int main(int argc, char* argv)

getnext(t, next);

while (s[i] && t[j]) //判斷字串是否結束

else //將t向右滑動

}} if (t[j] == '\0')

cout << "找到目標子串,從s中的第" << i - t[0] << "個位置開始!" << endl;

else

cout << "沒有匹配的目標子串!" << endl;

system("pause");

return 0;

}

字串匹配問題 KMP匹配演算法

基本思想 字串匹配問題 在文字串中尋找是否有與模式串相同的子串 在字串匹配時,暴力匹配忽略了如果模式串開頭與中間有重複部分,在將模式串的後面的重複部分匹配後,無法繼續匹配的話,此時將模式串開頭實際上也已經被匹配了,可以直接從開頭重複部分之後開始匹配 這裡引入了乙個部分匹配值表,每個與模式串的字元對應...

字串匹配問題 KMP演算法

kmp演算法 kmp是解字串匹配這類題目的演算法,又稱 看毛片 演算法。如下圖,給定乙個長度為n的文字,給定乙個長度為m 的字串,求該字串在給定文字的中出現的次數。kmp就是解決這一類題目的。i 1 zzkzzzkzzzkzkkkz zzkzzkzzkzzk j 1繼續考慮上面的問題。首先我相信每個...

KMP演算法 字串匹配問題

給定倆個字串str和match,長度分別為n和m。實現乙個演算法,如果字串str中含有字串match,則返回match在str中的開始位置,不含有則返回 1 str acbc match bc 返回2.str acbc match bcc 返回 1.我們知道在match中a區域與b區域是匹配的,所以...