KMP(自留笔记)
题目链接:28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)
例如:
文本串: a a b a a b a a f aabaabaaf aabaabaaf
模式串: a a b a a f aabaaf aabaaf
求next数组(前缀表)
next数组的表示方式有多种,如前缀表各项-1、各项右移等,这里直接使用前缀表不做处理
a | a | b | a | a | f |
---|---|---|---|---|---|
0 | 1 | 0 | 1 | 2 | 0 |
- 初始化(next数组和相关变量)
- 前后缀不相同的情况
- 前后缀相同
- 更新next的值
在求解过程中涉及到指针 i i i和指针 j j j
i:指向后缀末尾位置
j:指向前缀末尾位置,同时表示最长相等前后缀的长度
void getNext(int *next, const string& s){
//初始化
int j=0;
next[0]=0;
//因为next[0]=0,所以初始状态为两个字母,后缀的末尾是1
for(int i=1;i<s.size();i++){
//前后缀不相同
while(j>0 && s[i]!=s[j]) //连续回退至前后缀一致
{
j = next[j-1];//j指针回退,至j的前一位在前缀表对应的值
}
//前后缀相同
//如aa,j=0,i=1
if(s[i]==s[j]){
j++;
}
//更新next,j也表示最长相等前后缀的长度
next[i]=j;
}
}
对于求next[i],可看作前缀与后缀的一次匹配,求next过程实际上是dp,只与前一个状态有关:
- 若不匹配,一致往前退到0或者匹配位置
- 若匹配,则将之前的结果传递
当之前的结果不为0时,前后缀有相等的部分,所以j所指的实际上是与当前值相等的前缀,即之前的结果是可以传递的。
文本串与模式串的匹配
int strStr(string haystack, string needle) {
if(needle.size()==0){
return 0;
}
int next[needle.size()];
getNext(next,needle);
//用needle去匹配haystack,类似求next数组
int j=0;
//是两个串匹配,因此i和j都是从0开始
for(int i=0;i<haystack.size();i++){
while(j>0 && haystack[i]!=needle[j]){
j = next[j-1];//回退
}
if(haystack[i]==needle[j]){
j++;
}
if(j==needle.size()){//needle全部匹配完
return (i-needle.size()+1);//返回第一个匹配项的下标
}
}
return -1;
}