其实我感觉,写完本文我其实还不是特别透彻,也许在三刷或者更多刷的时候,或者说也许在未来的某一刻我会突然顿悟,到时候我可能还会更新一篇文章。希望这篇文章能够给你一些启发。即,使用模式串在文本串中匹配,看文本串中是否存在该模式串。class Solution {
public:
int strStr(string haystack, string needle) {
int hs = haystack.size();
int ns = needle.size();
for(int i = 0; i < hs;i++){
int tmp = i;// 保存开始匹配i的位置
for(int j = 0;j < ns;j++){
if(haystack[i] != needle[j]){
i = tmp;// 将i重置回去
break;
}else{
if(j == ns-1)return tmp;// 相等并且已经到达结尾模式串结尾
i++;// 继续走
}
}
}
return -1;
}
};其实j既是下标,也是计数。i则为控制当前所求的子串是哪个。下面我们好好说下j的作用,例如求:aabaa的最长相等前后缀,即next[4]。


j-1 i-1这两个对应的字符也相等),即s[j]==s[i],相等则推出s[j-1]+s[j]==s[i-1]+s[i],此时j=2。即next[4]=2。






这就是——利用已经匹配过的内容,继续匹配。class Solution {
public:
void getNext(int* next,const string s){
int n = s.size();
int j = 0;
next[0] = 0;
// i 为前缀末尾
// j 为后缀末尾
for(int i = 1; i < n ;i++){
while(j > 0 && s[i] != s[j]){// 控制回退,最多回退到开头,即j=0
j = next[j-1];
}
if(s[i] == s[j])j++;
next[i] = j;
}
}
// 本题中next数组的求与使用很相似。
int strStr(string haystack, string needle) {
int next[needle.size()];
// j负责遍历模式串
// i负责遍历文本串
getNext(next,needle);
int j = 0;
for(int i = 0;i < haystack.size();i++){
// 当前这个字符不同,通过移动j指针指向的模式串位置,来调整继续匹配的位置。
while(j > 0 && haystack[i] != needle[j]){
j = next[j-1];
}
if(haystack[i] == needle[j])j++;
if(j == needle.size()){
return i-needle.size()+1;
}
}
return -1;
}
};数组长度减去最长相同前后缀的长度相当于是第一个周期的长度,也就是一个周期的长度,如果这个周期可以被整除,就说明整个数组就是这个周期的循环。
class Solution {
public:
void getNext(int* next,const string& s){
int j = 0;
next[0] = 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[i] = j;
}
}
bool repeatedSubstringPattern(string s) {
if(s.size() == 0)return false;
int next[s.size()];
getNext(next,s);
int len = s.size();
// next[len-1] == 0就说明,以整体为子串的最长相等前后缀为0。
// 如果是通过某一子串重复得到的,以整体为子串的最长相等前后缀不会为0。
// 最小重复单位如果能被字符串的长度整除,说明该字符串是由重复的子串构成的。
if(next[len-1] != 0 && len % (len-(next[len-1])) == 0)return true;
return false;
}
};