Given a non-empty string s
, determine if it can be constructed by taking a substring of it and appending multiple copies of the substring together. In other words, check if s
is a repeated substring pattern. For example, for s = "abab"
, the answer is true
because it is "ab" + "ab". For s = "aba"
, the answer is false
.
s
of length between 1 and 10,000, consisting only of lowercase English letters.true
if s
can be constructed by repeating a substring, otherwise false
.The first idea that comes to mind is to try every possible substring length and see if repeating it forms the original string. This would involve checking all possible substring lengths from 1 up to half of the string's length, since a substring longer than half can't repeat at least twice.
However, this brute-force approach can be slow for long strings. To optimize, we can use mathematical properties and string manipulation techniques. For instance, if the length of s
is divisible by some k
, then s
could be made by repeating s[0:k]
exactly n // k
times. We need to check only these lengths.
There is also a clever trick: if we double the string (i.e., s + s
) and remove the first and last character, the original string s
should be found inside this new string if and only if s
is a repeated pattern. This is because the repeated pattern will overlap in the doubled string.
Let's break down the steps for the efficient solution:
t = s + s
.t
, resulting in t'
.s
appears in t'
, then s
is constructed by repeating a substring. Otherwise, it is not.s
is made by repeating a substring, then when you double it and remove the first and last character, the repeated pattern will cause s
to appear somewhere inside.s
is not a repeated pattern, then it will not appear in the modified double string.k
from 1 to len(s) // 2
:len(s) % k == 0
, check if repeating s[0:k]
len(s)//k
times equals s
.k
works, return true
. Otherwise, return false
.The string doubling trick is preferred for its conciseness and efficiency.
Let's take s = "abab"
as an example:
"abab" + "abab" = "abababab"
"bababab"
"abab"
appears in "bababab"
: Yes, at index 1.true
.
Now, try s = "aba"
:
"abaaba"
"baab"
"aba"
appears in "baab"
: No.false
.class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
return s in (s + s)[1:-1]
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string t = s + s;
return t.substr(1, t.size() - 2).find(s) != string::npos;
}
};
class Solution {
public boolean repeatedSubstringPattern(String s) {
String t = s + s;
return t.substring(1, t.length() - 1).contains(s);
}
}
var repeatedSubstringPattern = function(s) {
let t = s + s;
return t.slice(1, -1).includes(s);
};
Brute-force approach:
k
, we may have to build a repeated string of length n
and compare it to s
.n/2
such k
values.n
is the length of s
.s
in the doubled string (with first and last char removed) is O(n).The "Repeated Substring Pattern" problem can be solved efficiently using a clever string manipulation trick. By doubling the string, removing the first and last characters, and checking if the original string is present, we can determine in linear time whether the string is made from repeating a substring. This approach is elegant, concise, and avoids unnecessary brute-force checks, making it ideal for large input strings.