算法学习笔记【1】:KMP 算法
實際上這個算法很早就學了,但是那個時候并沒有了解的很清晰。 搞得好像現在有似的
首先,KMP 是三個人的名字。。。
首先,KMP 算法是用于字符串匹配的,時間復雜度為 O(n+m)O(n+m)O(n+m) [1]^{[1]}[1]。
Part 0:KMP 算法的誕生(可跳過)
我們假設有兩個字符串 s1s_1s1?,s2s_2s2?,其中 s1s_1s1? 為模式串,s2s_2s2? 為文本串。
首先我們考慮普通查找算法的時間復雜度,最壞會被卡到 O(nm)O(nm)O(nm)
為什么會這么慢?
加入我們的 s1s_1s1?,s2s_2s2? 長這樣 [2]^{[2]}[2]:
abababcabaa ababcabaa當 i=5i=5i=5 而 j=5j=5j=5 時,jjj 會直接跳回到 111,但是顯然,跳到 333 會更加快速,那么我該怎么讓電腦知道這個 jjj 跳到這里也行呢~
KMP 算法橫空出世!
使用 KMP 算法即可解決
Part 1:KMP 算法的思路
KMP 算法的精髓就在于一個數組 kmpkmpkmp 上。
這個數組可以記錄下當失配時 jjj 要跳到的地方。
這樣就可以方便快速的“智能”選擇。
那么匹配就變得十分簡單:【見下文 Part 2】
請讀者自行理解 kmpkmpkmp 數組的含義
那么 kmpkmpkmp 數組有什么含義?
注:此處的 i,j 含義與一般情況下不同
kmpkmpkmp 數組可以記錄下模式串在第 1?j1-j1?j 的位置中的最長的真前綴與真后綴相同的長度。
如此,我們就可以實現回跳時可以跳到最后的位置,以便繼續匹配。
接下來,我們就需要思考如何求出 kmpkmpkmp 數組。
這里我們考慮一個騷操作:自己匹配自己。
代碼見下文 Part 2
然后就結果了。
Part 2:Code
首先放代碼(洛谷 P3375 【模板】KMP字符串匹配):
#include<bits/stdc++.h> using namespace std; const int N=1e6+10; int n,m,kmp[N];//kmp 數組,懂得都懂 char s1[N],s2[N]; int main(){scanf("%s%s",s1+1,s2+1);n=strlen(s1+1),m=strlen(s2+1);int j=0; //kmp begin emm 這個只是我自己寫代碼的注釋 //這個就是自己匹配自己的操作for(int i=2;i<=m;i++){while(j&&s2[j+1]!=s2[i])j=kmp[j];if(s2[j+1]==s2[i])j++;kmp[i]=j;} //匹配文本串j=0;for(int i=1;i<=n;i++){while(j&&s2[j+1]!=s1[i])j=kmp[j];if(s2[j+1]==s1[i]){j++;if(j==m)cout<<i-m+1<<endl,j=kmp[j];}}for(int i=1;i<=m;i++)cout<<kmp[i]<<' '; //主要懶得寫注釋 //kmp endreturn 0; }Part 3: 時間復雜度分析
眾所周知,顯然,復雜度是 O(n+m)O(n+m)O(n+m)。
其實很簡單,因為 jjj 所進行的自增的次數不可能超過 mmm,因為 每次最多自增 111,會跳又不可能跳到比 000 更小,所以就只跳 n+mn+mn+m 次。
注:
-
[1]本文中 nnn,mmm 分別代表模式串和文本串的長度,同時 iii 表示文本串的索引,jjj 表示模式串的索引;
-
[2]此處的字符串借鑒了此文章:link;
總結
以上是生活随笔為你收集整理的算法学习笔记【1】:KMP 算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 压缩感知的尽头: 原子范数最小化
- 下一篇: 穿越之我是码农 1024 篇