Problem

Write a function that takes a string as input and returns the string reversed.

You must do this by modifying the input array in-place with O(1) extra memory.

Examples

Example 1

1
2
3
Input: s = "hello"
Output: "olleh"
Explanation: Characters are swapped moving inwards from both ends.

Example 2

1
2
3
Input: s = "kodeknight"
Output: "thginkedok"
Explanation: Standard two-pointer swapping until the middle.

Similar Problems

Reverse String 2

Solution

Below are multiple methods, ordered from the most standard (two pointers) to less typical (XOR swap, library helpers). All demonstrate the same logical reversal with different trade-offs.

Method 1 - Two Pointers (Canonical In-Place)

Intuition

Use one pointer at the left end and one at the right end; swap and converge. This minimizes space and is the standard interview solution.

Approach

Initialize l=0, r=n-1. While l < r, swap characters, increment l, decrement r.

Code

1
2
3
4
5
6
7
8
9
void reverseString(char *s) {
    int l = 0, r = (int)strlen(s) - 1;
    while (l < r) {
        char tmp = s[l];
        s[l] = s[r];
        s[r] = tmp;
        ++l; --r;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
    public void reverseString(char[] s) {
        // Initialize two pointers
        int left = 0;
        int right = s.length - 1;
        
        // Continue swapping while left pointer is less than or equal to right pointer
        while (left < right) {
            // Swap the characters at left and right positions
            char temp = s[left];
            s[left] = s[right];
            s[right] = temp;
            
            // Move towards the center
            left++;
            right--;
        }
    }
}
1
2
3
4
5
6
7
class Solution:
    def reverseString(self, s: list[str]) -> None:
        l, r = 0, len(s) - 1
        while l < r:
            s[l], s[r] = s[r], s[l]
            l += 1
            r -= 1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
pub fn reverse_string(s: &mut Vec<char>) {
	let mut left_index = 0;
	let mut right_index = s.len() - 1;
	while left_index < right_index {
		let temp = s[left_index];
		s[left_index] = s[right_index];
		s[right_index] = temp;
		left_index += 1;
		right_index -= 1;
	}
}

Complexity

  • ⏰ Time complexity: O(n) – each index swapped at most once.
  • 🧺 Space complexity: O(1) – in-place swaps only.

Method 2 - Symmetric Index Swap (Half Loop)

Intuition

Equivalent to Method 1 but frames the loop over the first half only; directly swaps i with n-i-1.

Approach

For i in [0 .. n/2), swap s[i] and s[n-1-i].

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Solution {
  public void reverseString(char[] s) {
    int n = s.length;
    for (int i = 0; i < n / 2; i++) {
      char tmp = s[i];
      s[i] = s[n - 1 - i];
      s[n - 1 - i] = tmp;
    }
  }
}
1
2
3
4
pub fn reverse_string(s: &mut [char]) {
    let n = s.len();
    for i in 0..n/2 { s.swap(i, n - 1 - i); }
}

Complexity

  • ⏰ Time complexity: O(n) – half the iterations, but still linear.
  • 🧺 Space complexity: O(1) – constant extra space.

Method 3 - Recursion

Intuition

Recurse inward: swap the outer pair then recurse on the substring interior. Pedagogical but less efficient due to call overhead.

Approach

Define helper recur(s, l, r): if l >= r stop; swap s[l], s[r]; call recur(l+1, r-1).

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
public class Solution {
    public void reverseString(char[] s) {
        helper(s, 0, s.length - 1);
    }

    private void reverseHelper(char[] s, int left, int right) {
        if (left >= right) {
            return;
        }

        // Swap the characters at left and right
        char temp = s[left];
        s[left] = s[right];
        s[right] = temp;

        // Recursive call to reverse the inner substring
        helper(s, left + 1, right - 1);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Solution:
    def reverse_string(self, s: list) -> None:
        self.helper(s, 0, len(s) - 1)
    
    def _reverse_helper(self, s: list, left: int, right: int) -> None:
        if left >= right:
            return
        
        # Swap the characters at left and right
        s[left], s[right] = s[right], s[left]
        
        # Recursive call to reverse the inner substring
        self.helper(s, left + 1, right - 1)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
pub fn reverse_string(s: &mut Vec<char>) {
	Self::reverse(&mut s[..]);
}

fn reverse(s: &mut [char]) {
	let len = s.len();
	if len < 2 {
		return;
	}

	s.swap(0, len - 1);

	Self::reverse(&mut s[1..len - 1]);
}

Complexity

  • ⏰ Time complexity: O(n) – each position processed once.
  • 🧺 Space complexity: O(n) – recursion stack depth ≈ n/2O(n) call frames.

Method 4 - Stack (Uses Extra Space)

Intuition

Push all characters, then pop to rebuild reversed order. Demonstrates LIFO data structure but wastes memory.

Approach

Traverse string pushing chars; pop sequentially and overwrite original array.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public class Solution {
    public void reverseString(char[] s) {
        Stack<Character> stack = new Stack<Character>();

        // Push all characters of the string onto the stack
        for (char c : s) {
            stack.push(c);
        }

        // Pop all characters from the stack and put them back into the string
        for (int i = 0; i < s.length; i++) {
            s[i] = stack.pop();
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Solution:
    def reverse_string(self, s: list) -> None:
        stack = []

        # Push all characters of the string onto the stack
        for char in s:
            stack.append(char)

        # Pop all characters from the stack and put them back into the string
        for i in range(len(s)):
            s[i] = stack.pop()

Complexity

  • ⏰ Time complexity: O(n) – one pass push + one pass pop.
  • 🧺 Space complexity: O(n) – stack stores all characters.

Intuition

Swaps two characters without a temporary variable using XOR: a ^= b; b ^= a; a ^= b;. Conceptually clever but modern compilers optimize a normal temp swap equally (or better). Less readable and can be error-prone if indices alias.

Approach

Same two-pointer convergence as Method 1, but uses XOR sequence instead of a temporary variable for each swap.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <string.h>
void reverseStringXor(char *s) {
    int l = 0, r = (int)strlen(s) - 1;
    while (l < r) {
        if (s[l] != s[r]) { // guard: XOR swap breaks if same address (not here) but ok to skip needless ops
            s[l] ^= s[r];
            s[r] ^= s[l];
            s[l] ^= s[r];
        }
        ++l; --r;
    }
}

Trade-offs

Readable temp-swap (Method 1) is preferred in production; XOR adds zero practical benefit and can inhibit some optimizations / confuse reviewers.

Complexity

  • ⏰ Time complexity: O(n) – identical iteration pattern to Method 1.
  • 🧺 Space complexity: O(1) – in-place.

Method 6 - Language Built-ins / Convenience

Intuition

Leverage library provisions: builder reversal or slicing constructs that internally perform efficient reversal (often similar to Method 1 under the hood).

Approach

Use high-level APIs to emphasize intent over mechanics.

Code

1
2
String s = "Game Plan";
String reversed = new StringBuilder(s).reverse().toString();
1
2
def reverse_builtin(s: str) -> str:
    return s[::-1]

Complexity

  • ⏰ Time complexity: O(n) – must copy / iterate through all characters.
  • 🧺 Space complexity: O(n) – new reversed buffer created.

Method Comparison

Method Time Space Notes
1 Two Pointers O(n) O(1) Canonical, optimal
2 Symmetric Half Loop O(n) O(1) Equivalent to Method 1 style variant
3 Recursion O(n) O(n) Educational; stack overhead
4 Stack O(n) O(n) Demonstrates stack; inefficient
5 XOR Swap O(n) O(1) No real benefit; readability cost
6 Built-ins O(n) O(n) Most concise; allocates new buffer

Notes

Preferred practical answer: Method 1 (or Method 2 variant). Include XOR only to illustrate bitwise swap patterns (see also Swap two number in place without temporary variables). Recursion and stack approaches are mainly pedagogical.