Given a string s, the task is to check if it can be constructed by taking a substring of it and appending multiple copies of the substring together.
Examples:
Input: s = "abcabcabc"
Output: true
Explanation: The given string is 3 times repetition of "abc"
Input: s = "abadabad"
Output: true
Explanation: The given string is 2 times repetition of "abad"
Input: s = "aabaabaabaab"
Output: true
Explanation: The given string is 4 times repetition of "aab"
Source: Google Interview Question
[Naive Approach] Using Substring Repetition Check ā O(n²) Time and O(n) Space
The idea is to try every possible substring length that can divide the original string length. For each valid length, we extract the substring and repeatedly concatenate it to form a new string. If the newly formed string becomes equal to the original string, then the given string is made by repeating that substring.
- Try all substring lengths from
1 to n/2 - Consider only lengths that exactly divide the string length
- Extract the substring and repeat it required number of times
- Compare the generated string with the original string and return result
[Efficient Approach] Using KMP (LPS Array) ā O(n) Time and O(n) Space
The idea is to use the Longest Prefix Suffix (LPS) array from the KMP algorithm. If a string is formed by repeating one of its substrings, then the string will have a proper prefix that is also a suffix. The last value of the LPS array gives the length of this repeating pattern. Using this value, we check whether the remaining substring length divides the total string length completely.
- Construct the LPS array for the given string using KMP preprocessing
- Find the length of the longest proper prefix which is also a suffix
- Compute the repeating substring length using
n - lps[n-1] - If the string length is divisible by this value, return true otherwise false
Why does this work?
Let us consider the two cases.
- String is actually a repetition : Then a large part of the prefix appears again at the end therefore LPS of last character becomes large. If there are exactly two repetitions, then there would not be any overlapping in prefix and suffix. Otherwise there would be an overlapping part in the common part of suffix and prefix. In both the cases, we get length of the repeating substring by subtracting LPS of last from total length.
- String is not a repetition : There are two cases here. If the LPS of last character is 0, then string is definitely not a repitiion. If LPS is not 0, for example, bbxxbb has LPS 2. In this case there is no common part which we check by checking divisibility of total length - LPS with the total length.