Check String Rotation using Concatenation
Problem and examples
Given two strings s1 and s2, your task is to check whether s2 is a rotation of s1.
- A string
s2is considered a rotation ofs1if you can take some characters from the start ofs1and move them to the end, in the same order, to gets2. - For example,
"erbottlewat"is a rotation of"waterbottle"because you can move"water"to the end to get"bottlewater"and then adjust the characters to match.
Return true if s2 is a rotation of s1, else return false.
| s1 | s2 | Output | Description |
|---|---|---|---|
| "waterbottle" | "erbottlewat" | true | s2 is a rotation of s1 |
| "hello" | "lohel" | true | Characters rotated from front to back |
| "abcd" | "cdab" | true | Valid rotation ("ab" moved to the end) |
| "abcd" | "acbd" | false | Characters are shuffled, not rotated |
| "abc" | "abcd" | false | Different lengths, cannot be rotations |
| "abcd" | "abce" | false | Same length, but different characters |
| "" | "" | true | Both strings are empty — considered valid rotation |
| "" | "a" | false | Empty string cannot rotate to form a non-empty string |
| "a" | "" | false | Non-empty string cannot match an empty one |
Explore Check if One String is a Rotation of Another
Load an example or enter your own input. Use the player controls to follow each change.
Understanding the Problem
We are given two strings, s1 and s2, and our task is to determine whether s2 is a rotation of s1. A rotation means that the characters in s1 can be moved around in a circular fashion to form s2.
For example, if s1 = "waterbottle", then any of the following are valid rotations: "erbottlewat", "lewaterbott", "ottlewaterb", etc.
A beginner-friendly way to think about it is: you can "cut" s1 at any position and swap the two parts — if you get s2, then it's a rotation.
Step-by-Step Solution with Example
step 1: Check Lengths
If two strings are not of the same length, they can never be rotations of each other. So, the first check should be:
if (s1.length !== s2.length) return false;
step 2: Concatenate s1 with itself
The key trick is this: If you take s1 and concatenate it with itself (s1 + s1), all possible rotations of s1 will be included in this new string.
let combined = s1 + s1;
step 3: Check if s2 is a substring of combined
Now we simply check whether s2 is a substring of combined. If it is, then s2 is a rotation of s1.
return combined.includes(s2);
step 4: Try with a Real Example
Let’s say s1 = "waterbottle" and s2 = "erbottlewat".
- Step 1: Length check – both are length 11 ✅
- Step 2: Concatenate
s1with itself –"waterbottlewaterbottle" - Step 3: Check if
s2is a substring of the above – Yes, it is! ✅
So the output will be true.
Edge Cases
- Case 1: Same strings – If
s1 = s2, then it's a rotation (rotation by 0 characters). - Case 2: Valid rotation –
s2can be formed by rotating characters from the front ofs1to the back. - Case 3: Different lengths – Return
falseimmediately. - Case 4: Same length, different characters – Even with equal lengths, mismatched content will return
false. - Case 5: Empty strings – Two empty strings are considered valid rotations. Return
true. - Case 6: One string empty – If only one is empty, return
false.
Finally
This solution is elegant, beginner-friendly, and efficient. It avoids manual rotation checks and uses string operations that are optimized in modern programming languages.
Time Complexity: O(n) — for substring search
Space Complexity: O(n) — due to the concatenated string
The core idea — doubling the string to expose all rotations — is a clever trick worth remembering.
- Check if lengths of
s1ands2are equal. If not, returnfalse. - Concatenate
s1with itself to create a new stringtemp = s1 + s1. - Check if
s2is a substring oftemp. - If yes, return
true; else, returnfalse.
Implementation and efficiency
C implementation
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int isRotation(char *s1, char *s2) {
if (strlen(s1) != strlen(s2)) return 0;
char *temp = malloc(strlen(s1) * 2 + 1);
strcpy(temp, s1);
strcat(temp, s1);
int result = strstr(temp, s2) != NULL;
free(temp);
return result;
}
int main() {
char s1[] = "abcde";
char s2[] = "deabc";
printf("Is Rotation: %s\n", isRotation(s1, s2) ? "true" : "false");
return 0;
}C++ implementation
#include <iostream>
using namespace std;
bool isRotation(string s1, string s2) {
if (s1.length() != s2.length()) return false;
string temp = s1 + s1;
return temp.find(s2) != string::npos;
}
int main() {
string s1 = "abcde";
string s2 = "deabc";
cout << "Is Rotation: " << (isRotation(s1, s2) ? "true" : "false") << endl;
return 0;
}Python implementation
def is_rotation(s1, s2):
if len(s1) != len(s2):
return False
temp = s1 + s1
return s2 in temp
s1 = "abcde"
s2 = "deabc"
print("Is Rotation:", is_rotation(s1, s2))Java implementation
public class StringRotationChecker {
public static boolean isRotation(String s1, String s2) {
if (s1.length() != s2.length()) return false;
String temp = s1 + s1;
return temp.contains(s2);
}
public static void main(String[] args) {
String s1 = "abcde";
String s2 = "deabc";
System.out.println("Is Rotation: " + isRotation(s1, s2));
}
}JavaScript implementation
function isRotation(s1, s2) {
if (s1.length !== s2.length) return false;
let temp = s1 + s1;
return temp.includes(s2);
}
const s1 = "abcde";
const s2 = "deabc";
console.log("Is Rotation:", isRotation(s1, s2));Go implementation
package main
import (
"fmt"
"strings"
)
func isRotation(s1, s2 string) bool {
if len(s1) != len(s2) {
return false
}
temp := s1 + s1
return strings.Contains(temp, s2)
}
func main() {
s1 := "abcde"
s2 := "deabc"
fmt.Println("Is Rotation:", isRotation(s1, s2))
}Rust implementation
fn is_rotation(s1: &str, s2: &str) -> bool {
if s1.len() != s2.len() {
return false;
}
let temp = format!("{}{}", s1, s1);
temp.contains(s2)
}
fn main() {
let s1 = "abcde";
let s2 = "deabc";
println!("Is Rotation: {}", is_rotation(s1, s2));
}Kotlin implementation
fun isRotation(s1: String, s2: String): Boolean {
if (s1.length != s2.length) return false
val temp = s1 + s1
return temp.contains(s2)
}
fun main() {
val s1 = "abcde"
val s2 = "deabc"
println("Is Rotation: ${isRotation(s1, s2)}")
}Swift implementation
func isRotation(_ s1: String, _ s2: String) -> Bool {
if s1.count != s2.count { return false }
let temp = s1 + s1
return temp.contains(s2)
}
let s1 = "abcde"
let s2 = "deabc"
print("Is Rotation: \(isRotation(s1, s2))")TypeScript implementation
function isRotation(s1: string, s2: string): boolean {
if (s1.length !== s2.length) return false;
const temp = s1 + s1;
return temp.includes(s2);
}
const s1 = "abcde";
const s2 = "deabc";
console.log("Is Rotation:", isRotation(s1, s2));Time complexity
| Case | Time | Explanation |
|---|---|---|
| best case | O(n) | We check the length and then perform a substring search which in most cases is linear time. |
| average case | O(n) | Checking if one string is in another (substring search) typically takes linear time in practice. |
| worst case | O(n^2) | In the worst case, depending on implementation of the `in` or `contains` function, substring search can be quadratic. |
Space complexity
O(n)
We create a temporary string which is double the size of s1, so extra space used is proportional to n.