day37【LeetCode力扣】459.重复的子字符串
1.题目描述
给定一个非空的字符串 s
,检查是否可以通过由它的一个子串重复多次构成。
示例 1:
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。
示例 2:
输入: s = "aba"
输出: false
示例 3:
输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)
提示:
1 <= s.length <= 104
s
由小写英文字母组成
2.题解
2.1c++【暴力】
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int s_length = s.size();
if (s_length <= 1)
return false;
for (int i = 1; i < s_length / 2+1; i++) {
if (s_length % i == 0) {
string t = s.substr(0, i);
string repeat="";
for (int j = 0; j < s_length / i; j++) {
repeat += t;
}
if(repeat == s)
return true;
}
}
return false;
}
};
两层for循环;
2.2c++【移动匹配】
当一个字符串s:abcabc,内部由重复的子串组成,也就是由前后相同的子串组成。
那么既然前面有相同的子串,后面有相同的子串,用 s + s,这样组成的字符串中,后面的子串做前串,前面的子串做后串,就一定还能组成一个s,所以判断字符串s是否由重复子串组成,只要两个s拼接在一起,里面还出现一个s的话,就说明是由重复子串组成。
当然,我们在判断 s + s 拼接的字符串里是否出现一个s的的时候,要刨除 s + s 的首字符和尾字符,这样避免在s+s中搜索出原来的s,我们要搜索的是中间拼接出来的s。
class Solution {
public:
bool repeatedSubstringPattern(string s) {
if(s.size()<=1)
return false;
string s2=s+s;
int n=s2.size();
string s3=s2.substr(1,n-2);
if(s3.find(s)!=std::string::npos)
return true;
else
return false;
}
};
或
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string t = s + s;
t.erase(t.begin()); t.erase(t.end() - 1); // 掐头去尾
if (t.find(s) != std::string::npos) return true; // r
return false;
}
};
2.3c++【KMP】
class Solution {
public:
void getNext(int* next, string& s) {
int j = 0;
next[0] = 0;
for (int i = 1; i < s.size(); i++) {
while (j > 0 && s[i] != s[j]) {
j = next[j - 1];
}
if (s[i] == s[j])
j++;
next[i] = j;
}
}
bool repeatedSubstringPattern(string s) {
if (s.size() <= 1)
return false;
int next[s.size()];
getNext(next, s);
int len = s.size();
if (next[len - 1] != 0 && len % (len - next[len - 1]) == 0) {
return true;
}
return false;
}
};
原理解释
- 前缀函数 (
next
数组):next[i]
表示字符串s[0:i]
的最长相等前缀和后缀的长度。例如,next[len - 1]
是整个字符串s
的前缀函数值。
- 判断条件:
next[len - 1]
是字符串的前缀函数的最后一个值,表示整个字符串的最长相等前缀和后缀的长度。len - next[len - 1]
计算出除去这个前缀的剩余部分的长度,即可能的最小重复子串的长度。
- 条件解释:
next[len - 1] != 0
确保字符串s
有非空的重复部分。即,字符串s
的前缀和后缀的长度不为零。len % (len - next[len - 1]) == 0
检查整个字符串的长度len
是否能被len - next[len - 1]
整除。这个条件验证了len - next[len - 1]
长度的子串是否可以重复填满整个字符串。
举例说明
假设 s = "abab"
,len = 4
,计算如下:
- 计算
next
数组:next = [0, 1, 2, 3]
next[len - 1] = next[3] = 3
- 计算子串长度:
len - next[len - 1] = 4 - 3 = 1
- 验证条件:
4 % 1 == 0
,满足条件。
因此,"abab"
可以由长度为 1 的子串 "a"
或 "b"
重复组成。但正确的最小重复子串是 "ab"
,长度为 2,检查中包含了所有可能的重复子串长度。
2.4python【暴力】
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
n = len(s)
for i in range(1,n//2+1):
if n%i==0:
sub = s[:i]
if sub*(n//i)==s:
return True
return False
2.5python【find】
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
return (s+s).find(s,1)!=len(s)
2.6python【前缀表(kmp)】
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
if len(s)<=1:
return False
next=[0]*len(s)
self.getNext(next,s)
if next[-1]!=0 and len(s)%(len(s)-next[-1])==0:
return True
return False
def getNext(self,next,s):
next[0]=0
j=0
for i in range(1,len(s)):
while j>0 and s[i]!=s[j]:
j=next[j-1]
if s[i]==s[j]:
j+=1
next[i]=j
return next
ok了,就到这里叭~~~
如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!
如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!
如果觉得作者写的不错,求给博主一个大大的点赞支持一下,你们的支持是我更新的最大动力!