LeetCode 62. 不同路徑
阿新 • • 發佈:2020-12-10
KMP可以解決什麼問題
如何在一個字串中查詢一個目標字串B是否出現在A中?
方法:暴力,用雙重迴圈,時間複雜度\(O(N\times M)\)
KMP原理詳解
暴力實在是太慢了!!!
我們可以先想一下,暴力演算法慢在哪裡
我們考慮如何加速
我們就進行了優化,首先我們預處理出一個表
然後就在匹配的時候如果成功,就\(i++,j++\)否則就\(j=next[j]\)。
於是這就可以快速匹配了。
KMP實現
求出\(next\)陣列的關鍵就是目標自己匹配自己。
我們用一個累加器來統計,如果匹配成功的話就繼續,同時累加器++,否則就累加器清零,然後\(j\)指標回到\(0\),重新giao一下就好了。
如果我們搞好了,我們就直接無腦匹配就可以了。
Code:
#include<iostream> #include<string> using namespace std; int nxt[1000005]; int len1, len2; void getNext(string s2) //求nxt陣列, 把目標串s2當作主串,把s2的字首當作目標串進行匹配 { nxt[0] = -1; //-1並沒有特殊的意義,下標跳到-1說明目標串第一個字元就跟主串不匹配 int i = 0, j = -1; // i表示最長公共字尾的末位下標, j表示最長公共字首的末尾下標 while(i < len2) { if(j == -1 || s2[i] == s2[j]) { i++; j++; nxt[i] = j; } else //當前綴與字尾的末尾下標不匹配時,字首的末位下標跳轉至 { j = nxt[j]; } } return ; } void KMP(string s1, string s2) //匹配函式,輸出s2在s1中出現的下標 { getNext(s2); //nxt陣列 int i = 0, j = 0; //i表示s1的下標, j表示s2的下標 while(i < len1) { if(j == len2 - 1 && s1[i] == s2[j]) //找到目標串 { cout << i - j + 1 << endl; //輸出目標串在s1中出現的起始位置 ,題目下標從1開始 j = nxt[j]; } if(j == -1 || s1[i] == s2[j]) //j == -1目標串第一個字元就不匹配,跟主串的下一個字元開始匹配 { i++; j++; } else //失配 { j = nxt[j]; } } return; } int main() { string s1, s2; cin >> s1 >> s2; len1 = s1.size(); len2 = s2.size(); KMP(s1, s2); for(int i = 1; i <= len2; i++) //P3375要求的是沒有右移過的nxt陣列,所以直接從下標1開始輸出 { cout << nxt[i] << " "; } return 0; }