String Reversal
Overview
String reversal is a fundamental string manipulation operation that involves reversing the order of characters in a string. While seemingly simple, string reversal problems test your understanding of two pointers, in-place algorithms, and efficient string manipulation techniques.
Common reversal problems include:
- Reverse entire string
- Reverse words in a string
- Reverse substring
- Reverse string in-place
- Reverse only vowels/consonants
- Reverse string with constraints
- Reverse k characters at a time
Pattern 1: Reverse Entire String
Reverse all characters in a string.
Approach 1: Two Pointers
function reverseString(s: string[]): void {
let left = 0;
let right = s.length - 1;
while (left < right) {
// Swap characters
[s[left], s[right]] = [s[right], s[left]];
left++;
right--;
}
}Time: O(n), Space: O(1)
Approach 2: Built-in Methods
function reverseStringBuiltIn(s: string): string {
return s.split('').reverse().join('');
}Time: O(n), Space: O(n)
Approach 3: Recursive
function reverseStringRecursive(s: string[]): void {
function reverse(left: number, right: number) {
if (left >= right) return;
[s[left], s[right]] = [s[right], s[left]];
reverse(left + 1, right - 1);
}
reverse(0, s.length - 1);
}Time: O(n), Space: O(n) for recursion stack
Pattern 2: Reverse Words in a String
Reverse the order of words while preserving spaces.
Example: "the sky is blue" → "blue is sky the"
Approach 1: Split and Reverse
function reverseWords(s: string): string {
return s.trim().split(/\s+/).reverse().join(' ');
}Time: O(n), Space: O(n)
Approach 2: Manual Reversal
function reverseWordsManual(s: string): string {
const words: string[] = [];
let word = '';
for (let i = 0; i < s.length; i++) {
if (s[i] === ' ') {
if (word) {
words.push(word);
word = '';
}
} else {
word += s[i];
}
}
if (word) words.push(word);
return words.reverse().join(' ');
}In-place reversal (O(1) space):
function reverseWordsInPlace(s: string[]): void {
// Reverse entire string
reverseRange(s, 0, s.length - 1);
// Reverse each word
let start = 0;
for (let i = 0; i <= s.length; i++) {
if (i === s.length || s[i] === ' ') {
reverseRange(s, start, i - 1);
start = i + 1;
}
}
}
function reverseRange(arr: string[], left: number, right: number): void {
while (left < right) {
[arr[left], arr[right]] = [arr[right], arr[left]];
left++;
right--;
}
}Time: O(n), Space: O(1)
Pattern 3: Reverse Substring
Reverse a specific substring within a string.
function reverseSubstring(s: string, start: number, end: number): string {
const arr = s.split('');
while (start < end) {
[arr[start], arr[end]] = [arr[end], arr[start]];
start++;
end--;
}
return arr.join('');
}Reverse substring in-place:
function reverseSubstringInPlace(s: string[], start: number, end: number): void {
while (start < end) {
[s[start], s[end]] = [s[end], s[start]];
start++;
end--;
}
}Time: O(k) where k is substring length, Space: O(1)
Pattern 4: Reverse Only Vowels
Reverse only vowel characters, keeping consonants in place.
function reverseVowels(s: string): string {
const vowels = new Set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']);
const arr = s.split('');
let left = 0;
let right = arr.length - 1;
while (left < right) {
// Find next vowel from left
while (left < right && !vowels.has(arr[left])) {
left++;
}
// Find next vowel from right
while (left < right && !vowels.has(arr[right])) {
right--;
}
// Swap vowels
if (left < right) {
[arr[left], arr[right]] = [arr[right], arr[left]];
left++;
right--;
}
}
return arr.join('');
}Example: "hello" → "holle"
Time: O(n), Space: O(1)
Pattern 5: Reverse Only Consonants
Reverse only consonant characters, keeping vowels in place.
function reverseConsonants(s: string): string {
const vowels = new Set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']);
const arr = s.split('');
let left = 0;
let right = arr.length - 1;
while (left < right) {
// Find next consonant from left
while (left < right && vowels.has(arr[left])) {
left++;
}
// Find next consonant from right
while (left < right && vowels.has(arr[right])) {
right--;
}
// Swap consonants
if (left < right) {
[arr[left], arr[right]] = [arr[right], arr[left]];
left++;
right--;
}
}
return arr.join('');
}Pattern 6: Reverse K Characters at a Time
Reverse every k characters in the string.
function reverseKChars(s: string, k: number): string {
const arr = s.split('');
for (let i = 0; i < arr.length; i += k) {
const end = Math.min(i + k - 1, arr.length - 1);
reverseRange(arr, i, end);
}
return arr.join('');
}
function reverseRange(arr: string[], left: number, right: number): void {
while (left < right) {
[arr[left], arr[right]] = [arr[right], arr[left]];
left++;
right--;
}
}Example: "abcdefg" with k=2 → "badcfeg"
Time: O(n), Space: O(1)
Reverse first k, keep next k, repeat:
function reverseKAlternating(s: string, k: number): string {
const arr = s.split('');
let i = 0;
while (i < arr.length) {
// Reverse first k
const end = Math.min(i + k - 1, arr.length - 1);
reverseRange(arr, i, end);
// Skip next k
i += 2 * k;
}
return arr.join('');
}Example: "abcdefgh" with k=2 → "bacdefgh" (reverse first 2, skip next 2)
Pattern 7: Reverse String with Constraints
Reverse string while preserving certain characters or positions.
Reverse but keep spaces:
function reverseKeepSpaces(s: string): string {
const arr = s.split('');
const spaceIndices = new Set<number>();
// Find space positions
for (let i = 0; i < arr.length; i++) {
if (arr[i] === ' ') {
spaceIndices.add(i);
}
}
// Collect non-space characters
const chars: string[] = [];
for (const char of arr) {
if (char !== ' ') {
chars.push(char);
}
}
// Reverse non-space characters
chars.reverse();
// Rebuild with spaces
const result: string[] = [];
let charIndex = 0;
for (let i = 0; i < arr.length; i++) {
if (spaceIndices.has(i)) {
result.push(' ');
} else {
result.push(chars[charIndex++]);
}
}
return result.join('');
}Reverse but keep special characters:
function reverseKeepSpecial(s: string): string {
const arr = s.split('');
const special = /[^a-zA-Z0-9]/;
const chars: string[] = [];
const positions: number[] = [];
// Collect alphanumeric characters and their positions
for (let i = 0; i < arr.length; i++) {
if (!special.test(arr[i])) {
chars.push(arr[i]);
positions.push(i);
}
}
// Reverse alphanumeric characters
chars.reverse();
// Place reversed characters back
for (let i = 0; i < positions.length; i++) {
arr[positions[i]] = chars[i];
}
return arr.join('');
}Pattern 8: Reverse Prefix/Suffix
Reverse a prefix or suffix of the string.
Reverse prefix of length k:
function reversePrefix(s: string, k: number): string {
if (k >= s.length) return s.split('').reverse().join('');
const arr = s.split('');
reverseRange(arr, 0, k - 1);
return arr.join('');
}Reverse suffix of length k:
function reverseSuffix(s: string, k: number): string {
if (k >= s.length) return s.split('').reverse().join('');
const arr = s.split('');
const start = arr.length - k;
reverseRange(arr, start, arr.length - 1);
return arr.join('');
}Reverse prefix until first occurrence of character:
function reversePrefixUntil(s: string, ch: string): string {
const index = s.indexOf(ch);
if (index === -1) return s;
const arr = s.split('');
reverseRange(arr, 0, index);
return arr.join('');
}Pattern 9: Reverse String by Words (Preserve Formatting)
Reverse words while preserving multiple spaces and formatting.
function reverseWordsPreserveSpaces(s: string): string {
const words: string[] = [];
const spaces: string[] = [];
let currentWord = '';
let currentSpace = '';
for (let i = 0; i < s.length; i++) {
if (s[i] === ' ') {
if (currentWord) {
words.push(currentWord);
currentWord = '';
}
currentSpace += ' ';
} else {
if (currentSpace) {
spaces.push(currentSpace);
currentSpace = '';
}
currentWord += s[i];
}
}
if (currentWord) words.push(currentWord);
if (currentSpace) spaces.push(currentSpace);
words.reverse();
const result: string[] = [];
const maxLen = Math.max(words.length, spaces.length);
for (let i = 0; i < maxLen; i++) {
if (i < words.length) result.push(words[i]);
if (i < spaces.length) result.push(spaces[i]);
}
return result.join('');
}Pattern 10: Reverse String in Chunks
Reverse string by dividing into chunks and reversing each chunk.
function reverseChunks(s: string, chunkSize: number): string {
const arr = s.split('');
for (let i = 0; i < arr.length; i += chunkSize) {
const end = Math.min(i + chunkSize - 1, arr.length - 1);
reverseRange(arr, i, end);
}
return arr.join('');
}Reverse chunks themselves (not characters within chunks):
function reverseChunkOrder(s: string, chunkSize: number): string {
const chunks: string[] = [];
for (let i = 0; i < s.length; i += chunkSize) {
chunks.push(s.substring(i, Math.min(i + chunkSize, s.length)));
}
return chunks.reverse().join('');
}Example: "abcdefgh" with chunkSize=2 → "ghefcdab" (chunks: ab, cd, ef, gh → reversed: gh, ef, cd, ab)
Pattern 11: Reverse String with Character Mapping
Reverse string while applying character transformations.
Reverse and swap case:
function reverseAndSwapCase(s: string): string {
const arr = s.split('');
let left = 0;
let right = arr.length - 1;
while (left < right) {
const temp = arr[left];
arr[left] = arr[right].toUpperCase() === arr[right]
? arr[right].toLowerCase()
: arr[right].toUpperCase();
arr[right] = temp.toUpperCase() === temp
? temp.toLowerCase()
: temp.toUpperCase();
left++;
right--;
}
return arr.join('');
}Reverse and apply transformation:
function reverseWithTransform(s: string, transform: (char: string) => string): string {
const arr = s.split('');
let left = 0;
let right = arr.length - 1;
while (left < right) {
[arr[left], arr[right]] = [transform(arr[right]), transform(arr[left])];
left++;
right--;
}
if (left === right) {
arr[left] = transform(arr[left]);
}
return arr.join('');
}Pattern 12: Reverse String Based on Condition
Reverse parts of string based on specific conditions.
Reverse only alphabetic characters:
function reverseAlphabetic(s: string): string {
const arr = s.split('');
const alphabetic: string[] = [];
const positions: number[] = [];
// Collect alphabetic characters
for (let i = 0; i < arr.length; i++) {
if (/[a-zA-Z]/.test(arr[i])) {
alphabetic.push(arr[i]);
positions.push(i);
}
}
// Reverse alphabetic characters
alphabetic.reverse();
// Place back
for (let i = 0; i < positions.length; i++) {
arr[positions[i]] = alphabetic[i];
}
return arr.join('');
}Reverse characters at even/odd indices:
function reverseEvenIndices(s: string): string {
const arr = s.split('');
const evenChars: string[] = [];
for (let i = 0; i < arr.length; i += 2) {
evenChars.push(arr[i]);
}
evenChars.reverse();
for (let i = 0, j = 0; i < arr.length; i += 2) {
arr[i] = evenChars[j++];
}
return arr.join('');
}When to Use String Reversal
Use reversal techniques when:
- Problem asks about "reverse", "flip", or "invert"
- Need to reverse words or substrings
- In-place modification is required
- Selective reversal (vowels, consonants, etc.)
- Pattern-based reversal (k characters, chunks)
- Palindrome or symmetric problems
Template (Basic Reversal)
function reverseTemplate(s: string[]): void {
let left = 0;
let right = s.length - 1;
while (left < right) {
[s[left], s[right]] = [s[right], s[left]];
left++;
right--;
}
}Template (Reverse Range)
function reverseRangeTemplate(arr: string[], left: number, right: number): void {
while (left < right) {
[arr[left], arr[right]] = [arr[right], arr[left]];
left++;
right--;
}
}Template (Selective Reversal)
function reverseSelectiveTemplate(s: string[], condition: (char: string) => boolean): void {
let left = 0;
let right = s.length - 1;
while (left < right) {
// Skip non-matching from left
while (left < right && !condition(s[left])) {
left++;
}
// Skip non-matching from right
while (left < right && !condition(s[right])) {
right--;
}
// Swap matching characters
if (left < right) {
[s[left], s[right]] = [s[right], s[left]];
left++;
right--;
}
}
}Time and Space Complexity Summary
- Basic reversal: O(n) time, O(1) space (in-place)
- Reverse words: O(n) time, O(n) space (split), O(1) space (in-place)
- Reverse substring: O(k) time where k is substring length, O(1) space
- Selective reversal: O(n) time, O(1) space
- Chunk reversal: O(n) time, O(1) space
Practice Tips
- Use two pointers — Most efficient for in-place reversal
- Handle edge cases — Empty strings, single character, all same characters
- Consider in-place — When space optimization is critical
- Preserve formatting — Be careful with spaces and special characters
- Optimize swaps — Use destructuring for cleaner code
- Test boundaries — Check start/end indices carefully
Common Mistakes
- Off-by-one errors — Be careful with array indices
- Not handling empty strings — Check length before processing
- Modifying during iteration — Be careful with in-place modifications
- Case sensitivity — Consider case when reversing selectively
- Space handling — Preserve or remove spaces as required
Related Concepts
- Two Pointers — Core technique for reversal
- String Manipulation — Building reversed strings
- In-Place Algorithms — Space-efficient reversal
- Palindrome Problems — Often use reversal techniques
String reversal is a fundamental operation that appears in many string problems. Master two-pointer reversal and in-place techniques, and you'll be well-prepared for reversal-related interview questions.