Problem Statement
Given two strings, s
and goal
, determine if goal
is a rotation of s
. A string goal
is considered a rotation of s
if we can take some leading number of characters from s
and append them to the end of s
to obtain goal
.
A shift on s consists of moving the leftmost character of s to the rightmost position.
For example, if s = "abcde", then it will be "bcdea" after one shift.
Examples
Example 1:
Input: s = "abcde", goal = "cdeab"
Output: true
Explanation : After performing 2 shifts we can achieve the goal string from string s.
After first shift the string s is => bcdea
After second shift the string s is => cdeab.
Example 2:
Input: s = "abcde", goal = "abced"
Output: false
Explanation : Any number of shift operations cannot convert string s to string goal.
Example 3
Input : s = "abcde" , goal = "abcde"
Output :
true
Constraints
- 1 <= s.length <= 100
- 1 <= goal.length <= 100
- s and goal consist of only lowercase English letters.
Approach
1️⃣ Iteration
Intuition
To address this problem, a solution could be to generate all possible rotations of the string and verify if any of these rotations match the target `goal` string. The approach involves systematically creating each rotation and comparing it against the `goal`, which ensures that if a matching rotation exists, it will be identified.
Approach
- First generate all possible rotations of the string by rearranging its character using the substring method.
- For each rotation created, check if it is the same as the goal string.
- If any rotation matches the goal, return true; otherwise, after testing all rotations, return false.
Dry Run
Initialization
index 0 1 2 3 4
-------------------------------
str | a | b | c | d | e |
-------------------------------
-------------------------------
goal | c | d | e | a | b |
-------------------------------
First Pass
index 0 1 2 3 4
-------------------------------
str | a | b | c | d | e |
-------------------------------
^
|
i = 0
rotated str => substr(i, n) and substr(0, i)
-------------------------------
str1 | a | b | c | d | e | + str2 (empty string)
-------------------------------
-------------------------------
goal | c | d | e | a | b |
-------------------------------
rotated str != goal
Increment 'i'
Second Pass
index 0 1 2 3 4
-------------------------------
str | a | b | c | d | e |
-------------------------------
^
|
i = 1
rotated str => substr(i, n) and substr(0, i)
------------------------- -------
str1 | b | c | d | e | + str2 | a |
------------------------- -------
-------------------------------
rotated str -> | b | c | d | e | a |
-------------------------------
-------------------------------
goal | c | d | e | a | b |
-------------------------------
rotated str != goal
Increment 'i'
Third Pass
index 0 1 2 3 4
-------------------------------
str | a | b | c | d | e |
-------------------------------
^
|
i = 2
rotated str => substr(i, n) and substr(0, i)
------------------- ---------------
str1 | c | d | e | + str2 | a | b |
------------------- ---------------
-------------------------------
rotated str -> | c | d | e | a | b |
-------------------------------
-------------------------------
goal | c | d | e | a | b |
-------------------------------
rotated str == goal
Returns TRUE
Code
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
bool rotateString(string& s, string& goal) {
// Strings must be same length to be rotations of each other
if (s.length() != goal.length()) {
return false;
}
// Try all possible rotations of s
for (int i = 0; i < s.length(); i++) {
string rotated = s.substr(i) + s.substr(0, i);
if (rotated == goal) {
return true;
}
}
return false;
}
};
int main() {
Solution sol;
string s = "abcde";
string goal = "cdeab";
cout << (sol.rotateString(s, goal) ? "true" : "false") << endl;
s = "abcde";
goal = "abced";
cout << (sol.rotateString(s, goal) ? "true" : "false") << endl;
return 0;
}
Complexity Analysis:
- Time Complexity:
O(N^2)
Generate N rotations and each comparison takes O(N) time. - Space Complexity:
O(N)
for the space needed to store each rotated string.
2️⃣ Optimal Approach
Intuition:
The optimal approach solves the problem by concatenating s with itself to form s + s. This way, all possible rotations of s are included as substrings in s + s, so we just need to check if goal is a substring of s + s.
Approach:
- Create a new string by concatenating s with itself, resulting in s + s.
- Check if goal is a substring of s + s.
- If goal is found within s + s, return true; otherwise, return false.
Dry Run:
index 0 1 2 3 4
-------------------------------
str | a | b | c | d | e |
-------------------------------
-------------------------------
goal | c | d | e | a | b |
-------------------------------
index 0 1 2 3 4
-------------------------------
str | a | b | c | d | e |
-------------------------------
-------------------------------
goal | c | d | e | a | b |
-------------------------------
Create a new string doubledStr = str + str
-------------------------------------------------------------
doubledStr | a | b | c | d | e | a | b | c | d | e |
-------------------------------------------------------------
^ ^
|-----------------------|
Search for goal in new string doubledStr
'goal' was found at index 2
Return TRUE
Code:
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
// Strings must be of the same length to be rotations of each other
bool rotateString(string& s, string& goal) {
if (s.length() != goal.length()) {
return false;
}
string doubledS = s + s; // Concatenate s with itself
return doubledS.find(goal) != string::npos; // Check if goal is a substring of s + s
}
};
int main() {
Solution sol;
string s = "abcde";
string goal = "cdeab";
cout << (sol.rotateString(s, goal) ? "true" : "false") << endl;
s = "abcde";
goal = "abced";
cout << (sol.rotateString(s, goal) ? "true" : "false") << endl;
return 0;
}
Complexity Analysis:
- Time Complexity:
O(N)
, because checking for a substring in s + s is linear in time. - Space Complexity:
O(N)
for the space needed to store the concatenated string s + s.