目录
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;
}