Day09——字符串
●28. 实现 strStr()
●459.重复的子字符串
●字符串总结
●双指针回顾
28.实现strStr()
思路:联系KMP算法,求解next数组
(next数组)前缀表:起始位置到下标i之前(包括i)的子串中,有多大长度的相同前缀后缀。
- next数组含义:next[j]表示模式串第 j 位前最长前缀等于后缀的长度。
- 求解next数组,要清楚流程:首先i表示前缀末尾,j表示后缀末尾
从 j = 0 开始,i = 1 此时前后缀才有意义;
解决 不匹配怎么办, 匹配怎么办, 更新数组三个步骤
void getNext(const string& s, vector<int>& next) {
int j = 0;
for(int i = 1; i < s.size(); i++) { //
while(j > 0 && s[i] != s[j]) { // 不匹配怎么办
j = next[j - 1]; // 不匹配向前回退,next[j-1]是当前已经完成匹配的最长相等前后缀, 因此直接回退到这里
}
if (s[i] == s[j]) // 匹配怎么办
j++; // 匹配上向后延伸
next[i] = j; // 更新next数组值
}
return;
}
怎么用next数组?就是和求next数组差不多的用法
int strStr(string haystack, string needle) {
if (needle.size() == 0) {
return 0;
}
vector<int> next(needle.size());
getNext(needle, next);
int 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()) { // 什么时候结束
return i - needle.size() + 1;
}
}
return -1;
}
459.重复的子字符串
思路:kmp算法的一次应用?
模式串的特质是最长相等前后缀,如果它可以由字串重复多次构成,那子串应该是这个前后缀的子集
好家伙,最长相等前后缀不包含的子串就是重复的子串。为啥,我再看看
解法一:若由重复子串构成,头尾相接一定有原串。
一个原串可以看作多个子串相接,即 aa aaa aaaa ,x = n a 那么头尾相接一定还可以组成新的原串理由就是 2n-2 >= n (n>1)
bool repeatedSubstringPattern(string s) {
string t = s + s;
t.erase(t.begin());
t.erase(t.end()-1);
if(t.find(s) != -1)
return true;
return false;
}
解法二:重复子串是最长相等前后缀不包含的那个。直接记结论,也没难记的。就当练习一下next数组求解吧。
void getNext(const string& s, vector<int>& next){
int j = 0; // j 表示前缀尾
next[0] = j;
for(int i = 1; i < s.size(); i++) { // i 是后缀末尾,i不能为0,否则无前后缀
while(j > 0 && s[i] != s[j]) { // 不匹配怎么办
j = next[j-1]; // next[j-1]是已经完成匹配的位置
}
if(s[i] == s[j])
++j;
next[i] = j;
}
return;
}
bool repeatedSubstringPattern(string s) {
int len = s.size();
vector<int> next(len);
getNext(s, next);
if(next[len-1] != 0 && len % (len-next[len-1]) == 0)
return true;
return false;
}