描述
给你一个文本串 T ,一个非空模板串 S ,问 S 在 T 中出现了多少次
要求:空间复杂度 O(len(S)),时间复杂度 O(len(S)+len(T))
输入:“ababab”,“abababab”
返回值:2
输入:“abab”,“abacabab”
返回值:1
解题思路
kmp算法参考
https://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
朴素方法慢是因为每次字符不相等时,模式串要退回到初始位置。可以利用之前的匹配信息排除掉多余的回退。关键点就是建立一个next数组来记录模式串索引应该回退的位置。
分别遍历主串和模式串,只要当前字符相等,模式串和主串均后移一位,如果不相等,模式串重新回退到next数组指定的下一位索引。
当模式串索引达到长度m时,说明全部匹配上了。此时将匹配次数加一,同时模式串索引j回退到next数组指定的下一位索引。
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 计算模板串S在文本串T中出现了多少次
* @param S string字符串 模板串
* @param T string字符串 文本串
* @return int整型
*/
int kmp(string S, string T) {
int m=S.size(),n=T.size();
if(m>n||n==0) return 0;
int cnt=0;
vector<int> next=getNext(S);
for(int i=0,j=0;i<n;i++){
while(j>0 && T[i]!=S[j]){
j=next[j-1];
}
if(T[i]==S[j]) j++;
if(j==m){
cnt++;
j=next[j-1];
}
}
return cnt;
}
//计算next数组
vector<int> getNext(string &S){
int m=S.size();
vector<int> next(m);
next[0]=0;
for(int i=1,j=0;i<m;i++){
//只要不相等,回退到next数组记录的下一位
while(j>0 && S[i]!=S[j]){
j=next[j-1];
}
if(S[i]==S[j]){
j++;
}
next[i]=j;
}
return next;
}
};