题目描述
给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。
示例 1
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。
示例 2
输入: s = "aba"
输出: false
示例 3
输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)
简单题我重拳出击,这道题一开始准备利用暴力的方法去做,但是感觉是简单题,我想着是一定有巧妙的解题思路。后面想出来以后发现其实和暴力的效果差不多,只是在解题思想上略胜一筹。后面查看官方接替文档,出现了KMP,一看到这个就感觉自己是个废物。由于对KMP已经忘得差不多的状态,等本菜鸟重新学习后在进行讲解,先说一说 “暴力” 和 “移位” 两种解题思路。
解题思路
1.暴力
如果一个长度为N的字符串S满足条件,那么S一定是由长度为n的子字符串s’ 拼接若干次(大于1次)构成。也一定满足下面的条件:
S=s's's'...
N是n的整数倍
s'[i] = S[i+kn] (0< = i< n , 0 <= k < N/n )
我们可以通过暴力的方式,将长度为n的子字符串s’找出来,然后遍历字符串S。进行上面条件的判断。
bool repeatedSubstringPattern(string s) {
int n = s.size();
for(int i = 1; i <= n/2; ++i) { //在S的一半长度都没有找到,说明该字符串不符合。
if(n % i == 0) { //若字符串S的长度不是当前子字符串长度的整数倍 直接跳过
int flag=1; //作为标记是否找到,找到提前返回
for(int j = i; j < n; ++j)//i代表着目前的搜索子字符串长度
if (s[j] != s[j - i]) {
flag=0;
break;
}
if(flag)
return 1;
}
}
return 0;
}
2.移位
我们已经知道 S=s’s’s’…,那么我们将S中的第一个子字符串s’移到S的最后去,形成的新字符串应该和S是相等的。我们可以通过多次移位得到子字符串。大概过程如下:
例如:S=abcabc
移位一次:cabcab
移位两次:bcabca
移位三次:abcabc
移位第三次得到字符串与S匹配,就可以得到S满足条件,子字符串s’=“abc”。
bool repeatedSubstringPattern(string s) {
int n=s.size();
string temp;
for(int i=1;i<=n/2;i++){ 在S的一半长度都没有找到,说明该字符串不符合。
temp=s.substr(i,n-i)+s.substr(0,i);//利用subtr(start,length)函数实现移位的操作
if(temp==s)
return 1;
}
return 0;
}
这种思路是正确的解题思路之一,不用怀疑这种思路。只是本人写的代码质量不高,虽然也能通过,但是所消耗的内存和运行时间大。看了大佬们的改进,利用了滑动窗户的思想+find内置函数,一行代码直接搞定,任重道远啊。
bool repeatedSubstringPattern(string s) {
return (s + s).find(s, 1) != s.size();//(s + s).find(s, 1)返回s.size()说明该字符串不满住
}
str1.find(str2,pos) #从str1的第pos个位置起,在字符串str1中寻找字符串str2,返回的是str1在str2中首次出现的位置。
读者可以运行下面的代码加深理解。
string s="abcd";
string ss=s+s; //ss="abcdabcd"
cout<<ss.find(s,0);//将0变成1,2,3,4,5试一试
3.KMP算法
先欠着,等学精通了补上。KMP算法