Given two strings, a
and b
, your task is to find the minimum number of times you need to repeat string a
such that string b
becomes a substring of the repeated string. If it is not possible for b
to be a substring no matter how many times you repeat a
, return -1
.
Key Constraints:
a
as many times as needed (concatenating copies of a
together).b
can never be a substring, return -1
.a
and b
are non-empty strings consisting of lowercase English letters.
The problem is about finding the smallest number of times we need to repeat a
so that b
appears somewhere inside the repeated string.
At first glance, a brute-force approach might be to keep repeating a
and checking if b
is a substring, but this could be inefficient for long strings.
To optimize, we can reason about the minimum necessary repetitions. Since b
must fit entirely within the repeated a
, the repeated string must at least be as long as b
. Sometimes, we might need to repeat a
once more to ensure b
can "wrap around" the end of one repetition and the start of the next.
So, the core idea is to repeat a
just enough times so that the repeated string is at least as long as b
, and possibly one or two more times to handle overlaps.
Let's break down the steps to solve this problem efficiently:
repeat_count = ceil(len(b) / len(a))
. This ensures the repeated string is at least as long as b
.b
is a substring of a
repeated repeat_count
times.b
might start at the end of one repetition and finish at the start of the next, so also check repeat_count + 1
repetitions.b
is found in either, return the corresponding repeat count.-1
.This approach is efficient because it only checks the minimal necessary repeated strings, rather than trying all possible repetitions.
Let's walk through an example for clarity.
Example: a = "abcd"
, b = "cdabcdab"
len(b) = 8
, len(a) = 4
.repeat_count = ceil(8 / 4) = 2
"abcd" * 2 = "abcdabcd"
."cdabcdab"
a substring of "abcdabcd"
? No.
"abcd" * 3 = "abcdabcdabcd"
."cdabcdab"
a substring of "abcdabcdabcd"
? Yes, starting at index 2.
3
.
Brute-force approach:
a
indefinitely and checks for b
at each step.a
and M is the length of b
.repeat_count + 1
repetitions.repeat_count + 1
, which is small (typically 2 or 3).The optimization comes from limiting the number of repetitions we check, making the approach efficient even for large inputs.
The key insight is that you only need to repeat a
just enough times to cover the length of b
, plus one extra in case b
wraps around. By calculating this minimum and checking only these cases, we avoid unnecessary work and solve the problem efficiently. This strategy leverages string properties and careful analysis of overlaps, resulting in a concise and elegant solution.
import math
class Solution:
def repeatedStringMatch(self, a: str, b: str) -> int:
repeat = math.ceil(len(b) / len(a))
repeated_a = a * repeat
if b in repeated_a:
return repeat
repeated_a += a
if b in repeated_a:
return repeat + 1
return -1
class Solution {
public:
int repeatedStringMatch(string a, string b) {
int repeat = (b.size() + a.size() - 1) / a.size();
string repeated_a = "";
for (int i = 0; i < repeat; ++i) {
repeated_a += a;
}
if (repeated_a.find(b) != string::npos)
return repeat;
repeated_a += a;
if (repeated_a.find(b) != string::npos)
return repeat + 1;
return -1;
}
};
class Solution {
public int repeatedStringMatch(String a, String b) {
int repeat = (int)Math.ceil((double)b.length() / a.length());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < repeat; ++i) {
sb.append(a);
}
if (sb.indexOf(b) != -1)
return repeat;
sb.append(a);
if (sb.indexOf(b) != -1)
return repeat + 1;
return -1;
}
}
var repeatedStringMatch = function(a, b) {
let repeat = Math.ceil(b.length / a.length);
let repeatedA = a.repeat(repeat);
if (repeatedA.indexOf(b) !== -1) return repeat;
repeatedA += a;
if (repeatedA.indexOf(b) !== -1) return repeat + 1;
return -1;
};