前置知识
- KMP的经典思想就是:当出现字符串不匹配时,可以记录一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配。
- 前缀表:next数组就是一个前缀表(prefix table)。前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。next数组也可以是前缀表加一之后的结果,方便进行代码的实现。
28. 找出字符串中第一个匹配项的下标
题目链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/
视频链接:https://www.bilibili.com/video/BV1PD4y1o7nd/
KMP算法:
总结:此题分两部分:先求next数组,接着进行匹配。
- 以下next数组的求法中,我将j=0,i=1;并设每一个数组元素表示除这个元素之外的前面的数组的最长公共前后缀
所以next[0]=-1;next[1]=0是固定的
关于怎么求next数组推荐:https://www.youtube.com/watch?v=GTJr8OvyEVQ - 在文本串和模式串匹配的过程中,文本串是一个一个的向后移动并进行比较的,所以时间复杂度是n,加上模式串求解next数组的时间复杂度m,所以总的时间复杂度为O(m+n)
class Solution {
public:
vector<int> getNext(string needle){
int j=0;
int len=needle.size();
vector<int> next;
//初始化,next前两个元素值是固定的(next元素值表示除它之外前面子数组的最大公共前后缀)
next.push_back(-1);
next.push_back(0);
for(int i=1;i<len-1;i++){
//当前后缀不相等,j向后回退
while(j>0&&needle[j]!=needle[i]){
j=next[j];//回到当前j所指向的next数组元素值对应的下标处
}
if(needle[j]==needle[i]) j++;
next.push_back(j);
}
return next;
}
int strStr(string haystack, string needle) {
vector<int> next=getNext(needle);
int res=-1;
int lenH=haystack.size();
int lenN=needle.size();
int i=0,j=0;
//出口为,既没有匹配成功,i也到了lenH
for(i;i<lenH;i++){
//不匹配,j回退,直到j=0或匹配为止
while(j>0&&haystack[i]!=needle[j]){
j=next[j];
}
//匹配的时候,j++
if(haystack[i]==needle[j]) j++;
//一旦出现了j=lenN,说明匹配成功,此时还没有i++
if(j==lenN) {
res=i-j+1;
return res;
}
}
return res;
}
};
459.重复的子字符串
文章链接:https://programmercarl.com/0459.重复的子字符串.html#算法公开课
视频链接:https://www.bilibili.com/video/BV1cg41127fw
题目链接:https://leetcode.cn/problems/repeated-substring-pattern/description/
方法一:移动匹配
s + s ,并刨除 s + s 的首字符和尾字符,这样避免在s+s中搜索出原来的s,我们要搜索的是中间拼接出来的s。
方法二:KMP算法
要点:最长前后缀剩余部分即可能为最小重复子串(剩余部分不可比s的一半的长度还大)
另外,如果剩余部分不可整除s,则说明也没有最小重复子串
例如:
由于这个题在解决的函数中需要用到前缀表,所以对于右移一位的next数组,最好不右移,直接使用前缀表表示的next数组。
class Solution {
public:
vector<int> getNext(string s){
int j=0,i=1;
vector<int> next;
//初始化next数组的头元素值(固定的)
next.push_back(0);
for(int i=1;i<s.size();i++){
//不相等
while(j>0&&s[i]!=s[j]){
j=next[j-1];
}
if(s[i]==s[j]) j++;
next.push_back(j);
}
return next;
}
bool repeatedSubstringPattern(string s) {
vector<int> next=getNext(s);
int size=next.size();
int remain=size-next[size-1];
//如果没有公共前后缀,或remain整除s,则false
if(next[size-1]==0||size%remain!=0) return false;
return true;
}
};
标签:补第,匹配,22,int,needle,next,数组,字符串,size
From: https://www.cnblogs.com/VickyWu/p/18457756