Minimum Time to Revert Word to Initial State I
MedPrompt
You are given a 0-indexed string word and an integer k.
At every second, you must perform the following operations:
- Remove the first
kcharacters ofword. - Add any
kcharacters to the end ofword.
Note that you do not necessarily need to add the same characters that you removed. However, you must perform both operations at every second.
Return the minimum time greater than zero required for word to revert to its initial state.
Example 1:
Input: word = "abacaba", k = 3
Output: 2
Explanation: At the 1st second, we remove characters "aba" from the prefix of word, and add characters "bac" to the end of word. Thus, word becomes equal to "cababac".
At the 2nd second, we remove characters "cab" from the prefix of word, and add "aba" to the end of word. Thus, word becomes equal to "abacaba" and reverts to its initial state.
It can be shown that 2 seconds is the minimum time greater than zero required for word to revert to its initial state.Example 2:
Input: word = "abacaba", k = 4
Output: 1
Explanation: At the 1st second, we remove characters "abac" from the prefix of word, and add characters "caba" to the end of word. Thus, word becomes equal to "abacaba" and reverts to its initial state.
It can be shown that 1 second is the minimum time greater than zero required for word to revert to its initial state.Example 3:
Input: word = "abcbabcd", k = 2
Output: 4
Explanation: At every second, we will remove the first 2 characters of word, and add the same characters to the end of word.
After 4 seconds, word becomes equal to "abcbabcd" and reverts to its initial state.
It can be shown that 4 seconds is the minimum time greater than zero required for word to revert to its initial state.
Constraints:
1 <= word.length <= 501 <= k <= word.lengthwordconsists only of lowercase English letters.
Approaches
2 approaches with complexity analysis and trade-offs.
This is a straightforward approach that iterates through the possible times t=1, 2, ... and for each time, checks if the condition for reverting to the initial state is met. The condition is that a suffix of the original word must match a prefix of the same length.
Algorithm
-
- Get the length of the word,
n.
- Get the length of the word,
-
- Start a loop for time
tfrom 1. The loop should continue as long ast * k < n.
- Start a loop for time
-
- Inside the loop, calculate the number of characters removed,
p = t * k.
- Inside the loop, calculate the number of characters removed,
-
- Check if the prefix of
wordof lengthn-pis equal to the suffix ofwordstarting at indexp. This can be done using string slicing and comparison.
- Check if the prefix of
-
- If they are equal, it means we can revert the word to its initial state. Return the current time
tas it's the minimum.
- If they are equal, it means we can revert the word to its initial state. Return the current time
-
- If the loop completes without finding such a
t, it means no periodt*kexists fort*k < n. The answer is then the smallesttsuch thatt*k >= n, which isceil(n/k). Return(n + k - 1) / k.
- If the loop completes without finding such a
Walkthrough
The problem can be rephrased as finding the smallest integer t > 0 such that word has a period of p = t * k. A string s of length n has a period p if its prefix of length n-p is equal to its suffix of length n-p (which starts at index p).
We can iterate t starting from 1. For each t, we calculate the potential period p = t * k.
We only need to check for p < n. If p >= n, it means we have conceptually removed at least n characters. In this scenario, we can always reconstruct the original word. The minimum time t for this to happen is ceil(n/k).
For each t where p = t*k < n, we check if word.substring(0, n - p) is equal to word.substring(p).
The first t that satisfies this condition is the minimum time required, so we return it.
If the loop finishes without finding such a t, it means no period t*k exists for t*k < n. The answer is then ceil(n/k).
class Solution { public int minimumTimeToInitialState(String word, int k) { int n = word.length(); for (int t = 1; t * k < n; ++t) { int p = t * k; // Check if word has period p. // This is equivalent to checking if the suffix of length n-p // is equal to the prefix of length n-p. // The suffix starts at index p. if (word.substring(p).equals(word.substring(0, n - p))) { return t; } } // If no such shorter period is found, the answer is the time // needed to remove at least n characters. return (n + k - 1) / k; }}A small optimization is to use word.regionMatches() to avoid creating new substring objects, which can be more efficient.
// Alternative check inside the loop// if (word.regionMatches(0, word, p, n - p)) {// return t;// }Complexity
Time
O(N^2 / K), where N is the length of the word. The loop runs up to `O(N/K)` times. In each iteration, creating and comparing substrings of length up to N takes `O(N)` time.
Space
O(N) in Java, where N is the length of the word. This is due to the creation of new substring objects in each iteration. If `regionMatches` is used, the space complexity is O(1).
Trade-offs
Pros
Simple logic that directly translates the problem's core condition.
Easy to implement and understand.
Sufficiently fast for the given constraints (
word.length <= 50).
Cons
Inefficient for very large strings due to repeated substring creation and comparison, leading to a quadratic time complexity in the worst case.
This approach improves upon the iterative search by using an advanced string algorithm, the Knuth-Morris-Pratt (KMP) algorithm's prefix function (LPS array). This allows us to find all possible periods of the string efficiently after a single linear-time scan, leading to a more optimal overall solution.
Algorithm
-
- Compute the Longest Proper Prefix Suffix (LPS) array for the
wordusing the KMP preprocessing algorithm. This takesO(N)time.
- Compute the Longest Proper Prefix Suffix (LPS) array for the
-
- The LPS array helps identify all 'borders' of the string. A string has a period
pif and only ifN-pis the length of one of its borders.
- The LPS array helps identify all 'borders' of the string. A string has a period
-
- We need the smallest
t > 0such thatp = t*kis a period. This is equivalent to finding the smallest periodpthat is a multiple ofk.
- We need the smallest
-
- This corresponds to finding the largest border length
Lsuch that(N-L)is a multiple ofk.
- This corresponds to finding the largest border length
-
- Iterate through the border lengths, starting from the longest (
L = lps[N-1]), then the next longest (lps[L-1]), and so on, until a border lengthLis found for which(N-L)is divisible byk.
- Iterate through the border lengths, starting from the longest (
-
- If such a border
Lis found, the minimum time is(N-L)/k.
- If such a border
-
- If no such border is found (including the empty border of length 0), the answer is
ceil(N/k).
- If no such border is found (including the empty border of length 0), the answer is
Walkthrough
The problem of finding the minimum time t can be reduced to finding the smallest t > 0 such that p = t*k is a period of the word. A key insight from stringology is that a string s of length N has a period p if and only if N-p is the length of a 'border' (a proper prefix that is also a suffix).
The KMP preprocessing algorithm is designed to find the longest border for every prefix of a string and stores these lengths in an LPS (Longest Proper Prefix Suffix) array. We can compute this array for word in O(N) time.
Once we have the LPS array, we can find the lengths of all borders of word. The longest border has length L1 = lps[N-1]. The next longest has length L2 = lps[L1-1], and so on. We are looking for the largest border length L such that the corresponding period p = N-L is a multiple of k. This will give us the smallest t = p/k.
We can iterate backwards through the border lengths and test the condition. The first one that satisfies it gives our answer. If no such border works, the only option is to remove characters until the word is empty, which takes ceil(N/k) seconds.
class Solution { public int minimumTimeToInitialState(String word, int k) { int n = word.length(); int[] lps = computeLPSArray(word); int longestMatch = lps[n - 1]; // Find the largest border length L such that (n - L) is a multiple of k. // This corresponds to the smallest period p = n - L that is a multiple of k. while (longestMatch > 0 && (n - longestMatch) % k != 0) { longestMatch = lps[longestMatch - 1]; } if ((n - longestMatch) % k == 0) { return (n - longestMatch) / k; } // If no such border is found, the answer is ceil(n/k). return (n + k - 1) / k; } private int[] computeLPSArray(String s) { int n = s.length(); int[] lps = new int[n]; for (int i = 1, len = 0; i < n;) { if (s.charAt(i) == s.charAt(len)) { len++; lps[i] = len; i++; } else { if (len != 0) { len = lps[len - 1]; } else { lps[i] = 0; i++; } } } return lps; }}Complexity
Time
O(N), where N is the length of the word. The LPS array computation takes O(N), and the subsequent search for the correct border also takes at most O(N).
Space
O(N) to store the LPS array.
Trade-offs
Pros
Highly efficient with a linear time complexity.
It is a deterministic approach, unlike hashing-based methods.
Provides the most optimal solution regardless of input size.
Cons
The implementation is more complex than the naive approach.
The KMP algorithm itself can be non-trivial to understand and implement correctly.
Solutions
Solution
class Solution: def minimumTimeToInitialState(self, word: str, k: int) -> int: n = len(word) for i in range(k, n, k): if word[i:] == word[: - i]: return i // k return (n + k - 1) // kclass Solution {public int minimumTimeToInitialState(String word, int k) { int n = word.length(); for (int i = k; i < n; i += k) { if (word.substring(i).equals(word.substring(0, n - i))) { return i / k; } } return (n + k - 1) / k; }}class Solution {public: int minimumTimeToInitialState(string word, int k) { int n = word.size(); for (int i = k; i < n; i += k) { if (word.substr(i) == word.substr(0, n - i)) { return i / k; } } return (n + k - 1) / k; }};Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.