重复的子字符串
给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。
1. 暴力匹配
列举不同子串长度,比较字符串
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int n = s.size();
for(int i=1;i<=n/2;i++){//当前分割长度
if(n%i!=0) continue;
string base = s.substr(0,i);
bool flag = true;
for(int index=i;index<n;index=index+i){
if(s.substr(index,i)!=base){flag = false; break;}
}
if(flag) return true;
}
return false;
}
};
列举长度,与前面进行逐个字符比较
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int n = s.size();
for(int i=1;i<=n/2;i++){//当前分割长度
if(n%i!=0) continue;
bool flag = true;
for(int index=i;index<n;index++){
if(s[index]!=s[index-i]){flag = false; break;}
}
if(flag) return true;
}
return false;
}
};
2. 正则表达式
regex re("(.+)\\1+"); //C++
class Solution {
public:
bool repeatedSubstringPattern(string s) {
return regex_match(s,re);
}
};
3. 技巧(数学证明)
循环字符串往左移位n次与原字符串匹配,这里用两个字符串叠加,然后去掉首尾,在其中找原字符串
class Solution {
public:
bool repeatedSubstringPattern(string s) {
return (s + s).find(s, 1) != s.size();
}
};
4. KMP算法
class Solution {
public:
bool kmp(const string& pattern) {
int n = pattern.size();
vector<int> fail(n, -1);
for (int i = 1; i < n; ++i) {
int j = fail[i - 1];
while (j != -1 && pattern[j + 1] != pattern[i])
j = fail[j];
if (pattern[j + 1] == pattern[i])
fail[i] = j + 1;
}
//上面已经计算出了每个位置的上一个相同值位置
//如果串由周期串构成,则两位置差就是周期串的长度,应该满足串长度是周期串长度整数倍
return fail[n - 1] != -1 && n % (n-1 - fail[n - 1]) == 0;
}
bool repeatedSubstringPattern(string s) {
return kmp(s);
}
};