题目
重复的子字符串
题面
给定一个非空的字符串 s
,检查是否可以通过由它的一个子串重复多次构成。
关键词
KMP,周期字符串问题
思路
方法一:
(官方题解)
暴力搜索所有子串,其要满足的条件是:
①s的长度是子串长度的倍数
②子串是s的前缀
③子串之后的所有字符满足s[i]==s[i-子串长度]
方法二:
(双倍字符串方法)
结论:把字符串翻一倍,掐头去尾,如果原字符串是该字符串的子串,那么原字符串是周期串。
证明见:https://writings.sh/post/algorithm-repeated-string-pattern
方法三:
(KMP求解)
公式:len(s)%(len(s)-maxLen)==0?true:false
其中maxLen为字符串s的最长公共前后缀长度
证明见:https://writings.sh/post/algorithm-repeated-string-pattern
代码
方法一
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int n = s.size();
for(int i=1;i*2<=n;i++){
if(n%i==0){
bool flag = true;
for(int j=i;j<n;j++){
if(s[j]!=s[j-i]){
flag = false;
break;
}
}
if(flag)
return true;
}
}
return false;
}
};
方法二:
class Solution {
public:
void getnext(int next[],string s){
next[0] = -1;
int i,j;
i=0;j=-1;
while(i<int(s.size())-1){
if(j==-1||s[i]==s[j])
next[++i]=++j;
else
j = next[j];
}
}
bool kmp(string s,string t){
int n = t.size();
int next[n];
getnext(next,t);
int i,j;
i=0;j=0;
while(i<int(s.size())&&j<int(t.size())){
if(j==-1||s[i]==t[j]){
i++;
j++;
}
else
j = next[j];
if(j>=int(t.size())){
return true;
}
}
return false;
}
bool repeatedSubstringPattern(string s) {
string t = s+s;
t.erase(0,1);
t.erase(t.size()-1,1);
if(kmp(t,s))
return true;
else
return false;
}
};
方法三
class Solution {
public:
void getnext(int next[],string s){
next[0] = -1;
int i,j;
i=0;j=-1;
while(i<int(s.size())-1){
if(j==-1||s[i]==s[j])
next[++i]=++j;
else
j = next[j];
}
}
bool repeatedSubstringPattern(string s) {
int n = s.size();
int next[n];
getnext(next,s);
int maxlen = next[n-1]+1;
if(maxlen==0||s[n-1]!=s[n-1-maxlen])
return false;
if(n%(n-maxlen)==0)
return true;
else
return false;
}
};
总结
菜
继续学习
也没理解为什么方法二比方法一慢
人晕,“下次再说”
参考
重复的子字符串 - 重复的子字符串 - 力扣(LeetCode)
https://writings.sh/post/algorithm-repeated-string-pattern
https://mp.weixin.qq.com/s?__biz=MzI0NjAxMDU5NA==&mid=2475925123&idx=1&sn=f94678a2382c0add786fa36f2384f96c&chksm=ff22f90ec85570189587e6b6d18b98a31c50f2f3271b2288ccde8657e4bde5c9b92cf93fe921&token=2007736410&lang=zh_CN#rd