The Rotate String problem asks you to determine whether one string (goal) can be obtained by rotating another string (s). A rotation means moving the leftmost character of the string to the rightmost position, and you can perform this operation any number of times (including zero).
Key constraints:
s and goal are non-empty strings of equal length.s any number of times (possibly zero).s becomes exactly equal to goal.s = "abcde", goal = "cdeab" → True (because rotating "abcde" two times gives "cdeab")
To solve this, let's first think about what it means to "rotate" a string. Every rotation moves the first character to the end, so after each rotation, the string changes slightly. If we try all possible rotations, we might eventually match goal.
The brute-force idea is: for each possible rotation (from 0 up to len(s) - 1), rotate s and check if it matches goal. But this involves creating a lot of intermediate strings, which is inefficient.
Is there a smarter way? Yes! Notice that if we double s (i.e., concatenate s with itself), all possible rotations of s are contained as substrings within this new string. So, we can simply check if goal is a substring of s + s.
Here’s how we can efficiently solve the problem:
s and goal are not the same length, it's impossible for one to be a rotation of the other. Return False immediately.
s with itself: This new string (s + s) contains all possible rotations of s as substrings.
goal appears anywhere in s + s, then goal is a rotation of s.
This approach avoids generating all rotations one by one and leverages efficient substring search.
Let's use the example s = "abcde" and goal = "cdeab":
s with itself: "abcdeabcde""cdeab" is a substring of "abcdeabcde":"cdeab" appears in "abcdeabcde".True because goal is a rotation of s.
If goal was "abced", it would not appear in "abcdeabcde", so we would return False.
Brute-force approach: For each possible rotation (up to n), create a new string and compare. Each comparison is O(n), so total is O(n2).
Optimized approach: Concatenating s is O(n), and checking if goal is a substring is O(n) (on average, due to efficient implementations like KMP or Boyer-Moore under the hood). So the total time is O(n).
Space complexity: O(n) for the concatenated string.
The key insight is realizing that all rotations of s are present as substrings in s + s. By checking if goal is a substring, we efficiently solve the problem in linear time and space. This approach avoids unnecessary repeated work and leverages string operations for a concise and elegant solution.
class Solution:
def rotateString(self, s: str, goal: str) -> bool:
if len(s) != len(goal):
return False
return goal in (s + s)
class Solution {
public:
bool rotateString(string s, string goal) {
if (s.length() != goal.length()) return false;
string ss = s + s;
return ss.find(goal) != string::npos;
}
};
class Solution {
public boolean rotateString(String s, String goal) {
if (s.length() != goal.length()) return false;
String ss = s + s;
return ss.contains(goal);
}
}
var rotateString = function(s, goal) {
if (s.length !== goal.length) return false;
return (s + s).includes(goal);
};