字符串 Part II
字符串包含子字符串 KMP算法
子字符串起始位
法1: 暴力求解
//暴力求解
int hayLen = haystack.length();
int needLen = needle.length();
if (hayLen < needLen) return -1;
//判断条件值得深思
for (int i = 0; i + needLen <= hayLen; ++i) {
bool flag = true;
for (int j = 0; j < needLen; ++j) {
if (haystack[i + j] != needle[j]){
flag = false;
break;
}
}
if (flag)
return i;
}
return -1;
法2: KMP算法
最长公共前后缀?摘自代码随想录
文章中字符串的前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串。
后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串。
正确理解什么是前缀什么是后缀很重要!
那么网上清一色都说 “kmp 最长公共前后缀” 又是什么回事呢?
我查了一遍 算法导论 和 算法4里KMP的章节,都没有提到 “最长公共前后缀”这个词,也不知道从哪里来了,我理解是用“最长相等前后缀” 更准确一些。
因为前缀表要求的就是相同前后缀的长度。
而最长公共前后缀里面的“公共”,更像是说前缀和后缀公共的长度。这其实并不是前缀表所需要的。
所以字符串a的最长相等前后缀为0。 字符串aa的最长相等前后缀为1。 字符串aaa的最长相等前后缀为2。 等等…。其中获取最长前缀表
//获取match 的next[] //s 模式串
vector<int> getNext(string s){
vector<int> next(s.length(),0);
int j = 0, len = s.length();
for (int i = 1; i < len; ++i) {
while(j > 0 && s[i] != s[j]){
j = next[j-1];
}
if (s[i] == s[j]) {
j++;
}// 找到相同的前后缀
next[i] = j;
}
return next;
}
//获取match 的vector<int>next
vector<int> ans = getNext( needle);
int len = haystack.length();
if (len == 0) return 0;
int j = 0;
for (int i = 0; i < len; ++i) {
while (j > 0 && haystack[i] != needle[j]){
j = ans[j - 1]; //回退
}
if (haystack[i] == needle[j]) j++;
if (j == needle.size())
return i-needle.size()+1;
}
return -1;
}
是否可由子串重复多次构成
459.重复的子字符串
法1: KMP
//获取match 的next[] //s 模式串
vector<int> getNext(string s){
vector<int> next(s.length(),0);
int j = 0, len = s.length();
for (int i = 1; i < len; ++i) {
while(j > 0 && s[i] != s[j]){
j = next[j-1];
}
if (s[i] == s[j]) {
j++;
}// 找到相同的前后缀
next[i] = j;
}
return next;
}
bool repeatedSubstringPattern(string s) {
//移动匹配
/* string ss = s + s;
ss.erase(ss.begin());
ss.erase(ss.end()-1);
if (ss.find(s) != string::npos)return true;
return false;*/
//KMP
if(s.size() == 0) return false;
vector<int> next = getNext(s);
int len = s.length();
if (next[len - 1] !=0 && len % (len - (next[len - 1])) == 0){
return true;
}
return false;
}