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);
};