1. 程式人生 > 其它 >KMP演算法簡析丨板子題

KMP演算法簡析丨板子題

暫且就先以一道洛谷板子題作為講解吧,

直接上程式碼,部分程式碼參考了優秀的大佬們的優秀的題解。(確實人家的碼風很好嗚嗚嗚)

 1 #include<bits/stdc++.h>
 2 #define ios ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
 3 typedef long long ll;
 4 //const ll mod = 1e9+7;
 5 //const ll mod = 1000003;
 6 #define endl "\n"
 7 using namespace std;
 8 
 9 const ll LEN = 1000001;
10
int KMP[LEN]; //用於記錄 當匹配到模式串的第i位之後失配 跳轉到模式串的位置的陣列 也可以理解為當前位置j前面的最長前後綴的長度 11 int len_s; //str主串的長度 12 int len_p; //pattern_str模式串的長度 13 int j; //用於模式串的指標,可以看作表示當前已經匹配完的模式串的最後一位的位置 14 //說人話就是 j表示模式串匹配到哪裡了 15 char s[LEN],p[LEN]; //主串和模式串的宣告 感覺string也可以 但是如果想從下標為1開始操作就不太方便了 而且string目測會慢一些
16 int main(){ 17 cin >> s + 1; //這裡+1的原因是讓操作的下標從1開始 18 cin >> p + 1; 19 len_s = strlen(s + 1); 20 len_p = strlen(p + 1); 21 j = 0; 22 for (int i = 2; i <= len_p; i++){ //讓模式串自己匹配自己獲取KMP陣列 23 while ( j && p[i] != p[j + 1]){ 24 j = KMP[j];
25 } 26 if(p[j + 1] == p[i]){ 27 j++; 28 } 29 KMP[i] = j; 30 } 31 j = 0; 32 for(int i = 1; i <= len_s; i++){ //與主串相比,從而輸出匹配位置 33 while(j > 0 && p[j+1] != s[i]){ 34 j = KMP[j]; 35 } 36 if (p[j + 1] == s[i]) { 37 j++; 38 } 39 if (j == len_p) { 40 cout << i - len_p + 1 << endl; 41 j = KMP[j]; 42 } 43 } 44 for (int i = 1; i <= len_p; i++){ 45 cout << KMP[i] << " "; 46 } 47 return 0; 48 }

這裡特別說明一下,將j指標回溯,其實等價於將模式串按照匹配的最長前後綴移動,這兩個的效果是一樣的。

實在不理解就畫個圖理解一下就理解了(什麼奇怪的句子)。

圖解:

初態:

第一次不匹配:

目前狀態的最長前後綴:j = 2

接下來開始回溯,注意,左邊是回溯,右邊是移動模式串,兩種方式等價:

現在,j移動到了2的位置。

 

 

於是我們就可以迴圈這個操作,直到得出結果。