String Reversal Tricks
Reversing a string (or parts of it) in-place solves a surprising range of problems: rotating a string, reversing word order, and cycling a sequence — all in O(n) time and O(1) extra space. The core trick is that two or three targeted reverse operations can rearrange any contiguous segment without allocating a new array.
Table of contents
- The fundamental trick
- The folded newspaper story
- The one idea to remember
- The reverse helper
- Application 1 — Rotate String left by k (LC #189 equivalent on strings)
- Application 2 — Reverse Words in a String (LC #151)
- Application 3 — Check if s2 is a rotation of s1 (LC #796)
- Application 4 — Reverse only words of length k
- Where to spot this pattern
- Common traps
- Check yourself
- Practice problems
The fundamental trick
Reversing a substring in place costs O(k) for a segment of length k and uses O(1) extra space (just a swap loop). Chaining two or three reversals transforms a string in sophisticated ways without any extra allocation.
The most important pattern:
To rotate a string left by
kpositions:
reverses[0..k-1], reverses[k..n-1], reverse the whole string.
The folded newspaper story
A real-life story
You have a newspaper with two sections: Local News (pages 1–4) and Sports (pages 5–8). You want Sports first. Instead of reprinting the newspaper, you:
- Flip the Local News section upside down.
- Flip the Sports section upside down.
- Flip the entire newspaper upside down.
The result: Sports is now in front, in the correct order. This is exactly the three-reversal rotation trick — flip each section, then flip the whole.
The one idea to remember
The entire pattern in one sentence
Any rotation or word-order flip can be achieved by two or three in-place segment reversals: reverse each part, then reverse the whole — transforming O(n) time, O(n) space into O(n) time, O(1) space.
The reverse helper
def reverse(s: list, left: int, right: int) -> None:
while left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
Note: Python strings are immutable. Convert to list(s) first, operate, then "".join(s).
Application 1 — Rotate String left by k (LC #189 equivalent on strings)
Rotate s left by k: "abcdefg", k=2 → "cdefgab"
def rotate_left(s: str, k: int) -> str:
n = len(s)
k %= n # handle k > n
arr = list(s)
reverse(arr, 0, k - 1) # reverse "ab" → "ba"
reverse(arr, k, n - 1) # reverse "cdefg" → "gfedc"
reverse(arr, 0, n - 1) # reverse whole → "cdefgab"
return "".join(arr)
Frame-by-frame: s = "abcdefg", k = 2
Original: a b c d e f g
Step 1 reverse [0,1]: b a c d e f g
Step 2 reverse [2,6]: b a g f e d c
Step 3 reverse [0,6]: c d e f g a b ✅
Application 2 — Reverse Words in a String (LC #151)
Given " the sky is blue ", return "blue is sky the".
Approach: trim, split on whitespace, reverse the word list.
def reverseWords(s: str) -> str:
return " ".join(s.split()[::-1])
s.split() with no argument handles multiple spaces and trims — one call does everything.
In-place O(1) space version (for languages without split, or when the interviewer asks):
def reverseWords_inplace(s: str) -> str:
arr = list(s.strip())
n = len(arr)
# Step 1: reverse entire string
reverse(arr, 0, n - 1)
# Step 2: reverse each individual word
start = 0
for i in range(n + 1):
if i == n or arr[i] == ' ':
reverse(arr, start, i - 1)
start = i + 1
return "".join(arr)
Frame-by-frame: "the sky blue"
After full reverse: "eulb yks eht"
After word reversal: "blue sky the" ✅
Application 3 — Check if s2 is a rotation of s1 (LC #796)
Is "cdab" a rotation of "abcd"?
Trick: s1 + s1 = "abcdabcd" — every rotation of s1 appears as a substring.
def isRotation(s1: str, s2: str) -> bool:
if len(s1) != len(s2):
return False
return s2 in (s1 + s1)
One line. O(n) time (KMP under the hood for in). O(n) space for the doubled string.
Application 4 — Reverse only words of length k
def reverseKWords(words: list[str], k: int) -> list[str]:
# reverse every group of k words
for i in range(0, len(words), 2 * k):
words[i: i + k] = words[i: i + k][::-1]
return words
Where to spot this pattern
Trigger words:
- "reverse words in a string"
- "rotate the string / array by k positions"
- "is one string a rotation of the other"
- "reverse every k characters"
- "in-place" combined with any rearrangement task
Common traps
Watch out for these
- Not reducing k modulo n. If
k >= n,k %= ngives the equivalent smaller rotation. Without this, you may reverse a negative or zero-length segment. - Mutating a Python string directly. Python strings are immutable. Always convert to
list(s)before in-place operations. - Extra spaces in Reverse Words.
" hello world ".split()handles leading, trailing, and multiple spaces correctly." hello world ".split(" ")does NOT — it produces empty strings. Use the no-argument version. - Reversing right boundary.
reverse(arr, 0, n-1)— right boundary isn-1, notn.
Remember this forever
String Reversal Tricks
Rotate left by k: reverse [0,k-1] → reverse [k,n-1] → reverse [0,n-1]
Reverse word order: " ".join(s.split()[::-1]) or full-reverse then per-word-reverse.
Rotation check: s2 in (s1 + s1) — O(n), one line.
Trap: k %= n always. Python strings are immutable — list(s) first.
Check yourself
Why does reversing the whole string, then reversing each word separately, produce the correct reversed-word-order result?
Reversing the full string puts each word in reversed character order AND reverses the order of words. Then reversing each individual word restores the correct character order within each word, leaving only the word order reversed. The two operations cancel out the character-level reversal while keeping the word-level reversal.
Why does `s2 in (s1 + s1)` detect all rotations of s1?
Every rotation of s1 by k positions starts at index k in s1 + s1. Specifically, (s1 + s1)[k : k + len(s1)] is exactly the rotation of s1 by k steps. Since k ranges from 0 to len(s1)-1, all rotations appear as contiguous substrings of s1 + s1. The in operator checks substring existence in O(n) using optimised search.
Practice problems
| Problem | Difficulty | What to notice | Link |
|---|---|---|---|
| Reverse Words in a String | Medium | s.split()[::-1] or three-reversal in-place | LC #151 |
| Rotate String | Easy | s2 in s1 + s1 — one line | LC #796 |
| Reverse String II | Easy | Reverse every first-k of 2k-block | LC #541 |
| Rotate Array | Medium | Same three-reversal trick, but on an integer array | LC #189 |
Next up: Character Frequency + Sorting — using frequency counts to sort or reorganize characters for problems like "Sort Characters by Frequency" and "Reorganize String."