1668. Maximum Repeating Substring
Problem Description
You are given two strings: sequence
and word
. Your task is to find how many times you can repeat the word
consecutively such that the resulting string appears as a substring within sequence
.
A string word
is considered k-repeating if when you concatenate word
exactly k
times, the result can be found as a substring in sequence
. For example, if word = "ab"
and k = 3
, then word * k = "ababab"
. If this appears in sequence
, then word
is 3-repeating.
The maximum k-repeating value is the largest value of k
for which word * k
appears as a substring in sequence
. If word
itself doesn't appear in sequence
at all, then the maximum k-repeating value is 0
.
The solution works by starting from the maximum possible value of k
(which is len(sequence) // len(word)
since we can't fit more repetitions than this) and checking downward. For each value of k
, it checks if word * k
exists as a substring in sequence
. The first k
value where this condition is true is the maximum k-repeating value, since we're checking from largest to smallest.
For example:
- If
sequence = "ababc"
andword = "ab"
, thenword * 2 = "abab"
is insequence
, butword * 3 = "ababab"
is not. So the maximum k-repeating value is2
. - If
sequence = "aaabaaaab"
andword = "aaa"
, thenword * 2 = "aaaaaa"
is not insequence
, butword * 1 = "aaa"
is. So the maximum k-repeating value is1
.
Intuition
The key insight is that if word
can be repeated k
times and found in sequence
, then it can also be repeated k-1
, k-2
, ... , 1
times and found in sequence
. This is because if a longer concatenated string exists as a substring, then any shorter version of it (with fewer repetitions) must also exist within that same substring.
For example, if "ababab"
(which is "ab" * 3
) exists in the sequence, then "abab"
("ab" * 2
) and "ab"
("ab" * 1
) must also exist, since they are contained within "ababab"
.
This monotonic property means we want to find the largest k
value that works. We could approach this in two ways:
- Start from
k = 1
and keep increasing until we find ak
whereword * k
is no longer insequence
- Start from the maximum possible
k
and work our way down until we find one that works
The second approach is more efficient because:
- The maximum possible value of
k
is bounded bylen(sequence) // len(word)
(we can't fit more repetitions than the sequence length allows) - We can stop as soon as we find the first working
k
value when searching from largest to smallest - Python's substring checking (
in
operator) is highly optimized, making the checkword * k in sequence
very fast
By starting from the maximum possible k
and checking downward, we guarantee finding the maximum k-repeating value with the fewest checks possible in the best case scenarios.
Learn more about Dynamic Programming patterns.
Solution Approach
The implementation uses a straightforward brute-force approach with an optimization to search from the maximum possible value downward.
Algorithm Steps:
-
Calculate the maximum possible k value:
len(sequence) // len(word)
- This represents the theoretical maximum number of times
word
could fit insequence
- For example, if
sequence
has length 10 andword
has length 3, the maximum possible k is10 // 3 = 3
- This represents the theoretical maximum number of times
-
Iterate from maximum k down to 0: Use a reverse range
range(len(sequence) // len(word), -1, -1)
- Starting from the largest possible value ensures we find the maximum k-repeating value first
- The range includes 0 to handle the case where
word
doesn't appear insequence
at all
-
Check if word * k exists in sequence: For each k value, concatenate
word
k times using Python's string multiplication (word * k
) and check if it's a substring ofsequence
using thein
operator- Python's
in
operator performs efficient substring matching - String multiplication
word * k
creates the concatenated string in O(k × len(word)) time
- Python's
-
Return immediately upon finding a match: Since we're checking from largest to smallest, the first k that satisfies the condition is our answer
Time Complexity Analysis:
- Let n =
len(sequence)
and m =len(word)
- Maximum iterations:
n // m + 1
- Each iteration creates a string of length up to n and performs substring matching in O(n)
- Overall time complexity: O(n²/m) in the worst case
Space Complexity: O(n) for storing the concatenated string word * k
at each iteration
The solution leverages Python's built-in string operations for simplicity and relies on the monotonic property that if k-repeating exists, then (k-1)-repeating must also exist, allowing us to find the maximum efficiently by searching from largest to smallest.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with sequence = "aaabaaaab"
and word = "aa"
.
Step 1: Calculate maximum possible k
len(sequence) = 9
,len(word) = 2
- Maximum possible k =
9 // 2 = 4
Step 2: Check from k = 4 down to k = 0
-
k = 4: Check if
"aa" * 4 = "aaaaaaaa"
(8 characters) is in"aaabaaaab"
- Looking for
"aaaaaaaa"
in sequence... NOT found ❌
- Looking for
-
k = 3: Check if
"aa" * 3 = "aaaaaa"
(6 characters) is in"aaabaaaab"
- Looking for
"aaaaaa"
in sequence... NOT found ❌
- Looking for
-
k = 2: Check if
"aa" * 2 = "aaaa"
(4 characters) is in"aaabaaaab"
- Looking at positions in sequence:
- Position 4-7:
"aaaa"
✓ FOUND!
- Position 4-7:
- Return k = 2
- Looking at positions in sequence:
The answer is 2 because "aa"
repeated twice ("aaaa"
) appears as a substring starting at index 4 in the sequence.
Note how we stop immediately after finding k = 2 works. We don't need to check k = 1 or k = 0 because we've already found our maximum. If we had started from k = 1 and worked upward, we would have had to check k = 1 (which works), k = 2 (which works), k = 3 (which doesn't work) to confirm that 2 is the maximum - requiring more checks overall.
Solution Implementation
1class Solution:
2 def maxRepeating(self, sequence: str, word: str) -> int:
3 # Calculate the maximum possible number of repetitions
4 # by dividing the length of sequence by the length of word
5 max_possible_k = len(sequence) // len(word)
6
7 # Iterate from the maximum possible k down to 0
8 # We start from the largest possible value for optimization
9 for k in range(max_possible_k, -1, -1):
10 # Check if word repeated k times exists as a substring in sequence
11 # word * k creates a string with word repeated k times
12 if word * k in sequence:
13 # Return the first (largest) k where the pattern is found
14 return k
15
16 # This line is technically unreachable since k=0 (empty string)
17 # will always be found in any string
18 return 0
19
1class Solution {
2 /**
3 * Finds the maximum k-repeating value of word in sequence.
4 * A k-repeating string is formed by concatenating word k times.
5 * Returns the maximum value k where word repeated k times is a substring of sequence.
6 *
7 * @param sequence the string to search within
8 * @param word the word to find repetitions of
9 * @return the maximum number of consecutive repetitions of word found in sequence
10 */
11 public int maxRepeating(String sequence, String word) {
12 // Calculate the maximum possible repetitions based on length constraints
13 int maxPossibleRepetitions = sequence.length() / word.length();
14
15 // Start from the maximum possible value and work downwards
16 // This ensures we find the maximum k value first
17 for (int k = maxPossibleRepetitions; k > 0; k--) {
18 // Create a string by repeating word k times
19 String repeatedWord = word.repeat(k);
20
21 // Check if this k-repeated word exists as a substring in sequence
22 if (sequence.contains(repeatedWord)) {
23 // Return immediately when we find the first (and largest) match
24 return k;
25 }
26 }
27
28 // If no repetitions found, return 0
29 return 0;
30 }
31}
32
1class Solution {
2public:
3 int maxRepeating(string sequence, string word) {
4 // Initialize the maximum k-repeating value
5 int maxK = 0;
6
7 // Build the repeated word string starting with one occurrence
8 string repeatedWord = word;
9
10 // Calculate the maximum possible repetitions based on lengths
11 int maxPossibleRepetitions = sequence.size() / word.size();
12
13 // Try each possible k-repeating value from 1 to maximum
14 for (int k = 1; k <= maxPossibleRepetitions; ++k) {
15 // Check if the current repeated pattern exists in the sequence
16 if (sequence.find(repeatedWord) != string::npos) {
17 // Update the maximum k value if pattern is found
18 maxK = k;
19 }
20
21 // Append word to create the next k-repeating pattern
22 repeatedWord += word;
23 }
24
25 return maxK;
26 }
27};
28
1/**
2 * Finds the maximum number of times a word can be repeated consecutively in a sequence
3 * @param sequence - The string to search within
4 * @param word - The word to find repeated occurrences of
5 * @returns The maximum k-repeating value where word repeated k times exists in sequence
6 */
7function maxRepeating(sequence: string, word: string): number {
8 // Get the length of the sequence string
9 const sequenceLength: number = sequence.length;
10
11 // Get the length of the word to search for
12 const wordLength: number = word.length;
13
14 // Calculate the maximum possible repetitions (sequence length divided by word length)
15 const maxPossibleRepetitions: number = Math.floor(sequenceLength / wordLength);
16
17 // Start from the maximum possible repetitions and work downwards
18 for (let repetitionCount: number = maxPossibleRepetitions; repetitionCount > 0; repetitionCount--) {
19 // Create a string with the word repeated 'repetitionCount' times
20 const repeatedWord: string = word.repeat(repetitionCount);
21
22 // Check if this repeated pattern exists in the sequence
23 if (sequence.includes(repeatedWord)) {
24 // Return the first (largest) repetition count that matches
25 return repetitionCount;
26 }
27 }
28
29 // No repetitions found, return 0
30 return 0;
31}
32
Time and Space Complexity
Time Complexity: O(n * m * k)
where n
is the length of sequence
, m
is the length of word
, and k
is the maximum possible value of repeating which is n // m
.
The algorithm iterates from k = n // m
down to 0
. For each value of k
, it:
- Creates a string
word * k
which takesO(m * k)
time - Checks if this string is a substring of
sequence
using thein
operator, which takesO(n * m * k)
time in the worst case (the substring search needs to compare up tom * k
characters at each of then
positions)
Since we iterate at most n // m + 1
times, the total time complexity is O((n // m) * n * m * k)
. In the worst case where k ≈ n // m
, this simplifies to O(n² * m)
.
Space Complexity: O(m * k)
where k
can be at most n // m
.
The algorithm creates a temporary string word * k
in each iteration, which requires O(m * k)
space. The maximum value of k
is n // m
, so the worst-case space complexity is O(n)
. The space is not accumulated across iterations since each temporary string is discarded before the next one is created.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Overlapping Pattern Misunderstanding
A common misconception is thinking that overlapping occurrences of word
should be counted separately. For example, if sequence = "aaaa"
and word = "aa"
, one might incorrectly think the answer is 3 (counting "aa" at positions 0, 1, and 2). However, the problem asks for consecutive repetitions, meaning word * k
must appear as a continuous substring. The correct answer is 2 since "aaaa" contains "aa" * 2 = "aaaa" but not "aa" * 3 = "aaaaaa".
Solution: Always remember that we're looking for word
repeated k times consecutively as a single substring, not counting overlapping occurrences.
2. Inefficient Bottom-Up Approach
A natural but inefficient approach is to start from k=1 and increment until word * k
is no longer found:
k = 0 while word * (k + 1) in sequence: k += 1 return k
While this works, it's less efficient when the maximum k is small relative to len(sequence) // len(word)
.
Solution: The provided top-down approach is generally more efficient as it can terminate early when k is large, avoiding unnecessary string constructions and comparisons for smaller k values.
3. Integer Division Edge Cases
When len(word) > len(sequence)
, the integer division len(sequence) // len(word)
returns 0, which is correct. However, developers might forget to handle this case or might use regular division /
instead of integer division //
, causing type errors.
Solution: Always use integer division //
and ensure the range includes 0 to handle cases where word
doesn't appear in sequence
at all.
4. Memory Overhead with Large Strings
For very large sequences and small words, creating word * k
for large k values can consume significant memory. For instance, if word = "a"
and sequence
is very long, we might create very large intermediate strings.
Solution: For memory-critical applications, consider using string matching algorithms that don't require full string construction, such as:
def maxRepeating(self, sequence: str, word: str) -> int:
max_k = len(sequence) // len(word)
for k in range(max_k, -1, -1):
# Use string search with calculated length instead of construction
pattern_length = k * len(word)
found = False
for i in range(len(sequence) - pattern_length + 1):
match = True
for j in range(pattern_length):
if sequence[i + j] != word[j % len(word)]:
match = False
break
if match:
found = True
break
if found:
return k
return 0
Consider the classic dynamic programming of longest increasing subsequence:
Find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.
For example, the length of LIS for [50, 3, 10, 7, 40, 80]
is 4
and LIS is
[3, 7, 40, 80]
.
What is the recurrence relation?
Recommended Readings
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!