又码了一遍KMP...发现如果不看书一开始还是自己码不出来...一定要理解啊!!!
注意next数组其实在做next[i+1]。而判断查找到完整子串的依据是看子串的下标是否“走到底”了。
这道题其实就用KMP就行了。只不过它默认是string类型的,而我模板是针对“以1为开始下标的char数组”,所以要通过遍历转存一下。
·不知道为什么没有AC全部的代码:
class Solution {
public:
// KMP算法 理解和模板见https://blog.csdn.net/m0_38033475/article/details/80281903,但我这里注释够了
// 两个part:基于子串构造next数组 + 查询子串
// next表示,若下一个字符不匹配,则要转到哪个状态去。next[i]表示字符串的0~next[i]和i-next[i]+1~i相同,可理解为具有相同前缀
int next[50005];
void getNext(string sub) // next数组的构造可以认为是子串自身与自身匹配,过程中给next数组赋值
{
// 默认字符串下标要从1开始
next[1] = 0;
for(int i=2; i<sub.length(); i++)
{
int j = next[i-1]; // 上一个字符所处的状态
while(sub[j+1]!=sub[i] && j>0) // 看看当前字符是否匹配,从而决定转移到哪个状态,再开始匹配当前字符
j = next[j];
if(sub[j+1] == sub[i])
next[i] = j+1;
else
next[i] = 0; // 得从头开始
}
}
int searchSub(string s, string sub)
{
// 默认字符串下标要从1开始
int j = 0; // 初始状态,表示子串从头开始匹配
for(int i=1; i<s.length(); i++)
{
while(sub[j+1]!=s[i] && j>0) // 子串的下一个状态(字符)若匹配失败,则向前找拥有共同前缀的最近位置
j = next[j];
if(sub[j+1]==s[i]) // 当前匹配成功继续向后转移状态
j++;
if(j>=sub.length()-1) // 全部匹配成功,返回匹配到的子串的起始位置;注意这里是最后一个下标即可,因为这里我总是向后处理的,走到最后一个下标说明最后一个下标已匹配成功
return i-sub.length()+1;
}
return -1;
}
int strStr(string haystack, string needle) {
if(haystack.length()==0 && needle.length()==0)
return 0;
else if(haystack.length()==0 && needle.length()!=0)
return -1;
else if(haystack.length()!=0 && needle.length()==0)
return 0;
// 注意先让两个字符串都从下标1开始
haystack = "0" + haystack;
needle = "0" + needle;
getNext(needle);
return searchSub(haystack, needle);
}
};
2022.3 更新AC代码