目錄
KMP要求模式串一頭一尾能匹配上
解釋: j=6時候,match = 3,意思是p0-p3是能夠和p(6-3)-p6匹配。
注意:當有一個串能配得上,並不能到此爲止,要繼續檢查還有沒有更長的串。
KMP時間複雜度
match函數
優秀的做法:
首先j-1位置和match【j-1】位置匹配
然後考慮j位置和match[j-1]+1位置是否匹配?如果匹配
如果match[j]>match[j-1]+1,考慮向前一個位置A
如果能匹配,則後面字符都能匹配。
一旦出現這種情況,意味着A-X能匹配上,意味着對於0到j-1這個子串來說他的macth值應該指向X,match[j-1]+1的位置。這是不可能的。用反證法證明:
match[j] = match[j-1]+1
當j位置和match[j-1]+1不匹配,查看前match[j-1]是否有匹配的
遞歸的查看
比較兩個?的位置,即比較j和match[match[j-1]] +1(回溯)
如果能夠匹配
match[match[j - 1]] +1 = match[j]
match的實現
match的時間複雜度
O(m)平方是上界
具體代碼實現:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<int> buildMatch(string p) {
int len = p.size(), k = -1, j = 0;//k表示和j匹配,也表示匹配從0到k
vector<int> match(len, -1);//初始化爲-1
while (j < len - 1) {
if (k == -1 || p[j] == p[k]) {
++k; ++j;
match[j] = (p[j] != p[k]) ? k : match[k];//要避免出現p[j] == p[match[j]]的情況
} else {
k = match[k];
}
}
return match;
}
int kmp(string s, string p) {
int m = s.size(), n = p.size();
if(m < n) return -1;
vector<int> match = buildMatch(p);
int i = 0, j = 0;
while (i < m && j < n) {
if (j == - 1 || s[i] == p[j]) {
++i; ++j;
} else {
j = match[j];
}
}
return (j == n) ? i - j : -1;
}
int main() {
string s,p;
cin>>s>>p;
cout << kmp(s, p) << endl;
}