Facebook Pixel

344. Reverse String

Problem Description

You need to reverse a string that is given as an array of characters. The task requires you to modify the original array directly without creating a new array or using additional data structures.

Key Requirements:

  • The input is an array of characters s representing a string
  • You must modify the array in-place (directly change the original array)
  • You can only use O(1) extra memory, meaning you cannot create another array or use space proportional to the input size
  • The function should not return anything; it should only modify the input array

Example: If the input array is ['h', 'e', 'l', 'l', 'o'], after calling the function, the array should become ['o', 'l', 'l', 'e', 'h'].

The solution uses a two-pointer technique where one pointer i starts at the beginning of the array (index 0) and another pointer j starts at the end (index len(s) - 1). The algorithm repeatedly swaps the characters at positions i and j, then moves i forward and j backward. This process continues until the pointers meet in the middle, at which point the entire string has been reversed.

The swapping is done using Python's tuple assignment: s[i], s[j] = s[j], s[i], which exchanges the values at the two positions without needing a temporary variable. This approach ensures the space complexity remains O(1) as required.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

To reverse a string in-place, think about what "reversing" actually means - the first character should become the last, the second character should become the second-to-last, and so on. This naturally suggests a swapping pattern.

Consider a simple example: ['a', 'b', 'c', 'd']. To reverse it:

  • 'a' (at position 0) should swap with 'd' (at position 3)
  • 'b' (at position 1) should swap with 'c' (at position 2)

Notice that we're pairing elements from opposite ends and working our way toward the center. This observation leads us to the two-pointer approach:

  • Start with one pointer at the beginning and another at the end
  • Swap the elements they point to
  • Move both pointers toward the center
  • Stop when they meet or cross

Why does this work with O(1) space? Because we're only using two integer variables (i and j) to track positions, regardless of the array size. We're rearranging elements within the existing array rather than creating a new one.

The beauty of this approach is its symmetry - we process the array from both ends simultaneously, completing the reversal in exactly n/2 swaps where n is the array length. For odd-length arrays, the middle element naturally stays in place, which is exactly what we want.

Solution Approach

The implementation uses the two-pointer technique to reverse the string in-place:

  1. Initialize two pointers: Set i = 0 to point to the first character and j = len(s) - 1 to point to the last character.

  2. Swap and move pointers: While i < j:

    • Swap the characters at positions i and j using Python's tuple assignment: s[i], s[j] = s[j], s[i]
    • Move i forward by incrementing it: i = i + 1
    • Move j backward by decrementing it: j = j - 1
  3. Termination condition: The loop continues as long as i < j. When i >= j, the pointers have either met (for even-length arrays) or crossed (for odd-length arrays), meaning all necessary swaps are complete.

Step-by-step example with s = ['h', 'e', 'l', 'l', 'o']:

  • Initial: i = 0, j = 4, array = ['h', 'e', 'l', 'l', 'o']
  • Iteration 1: Swap s[0] and s[4] โ†’ ['o', 'e', 'l', 'l', 'h'], then i = 1, j = 3
  • Iteration 2: Swap s[1] and s[3] โ†’ ['o', 'l', 'l', 'e', 'h'], then i = 2, j = 2
  • Stop: i is not less than j, so we exit the loop

The algorithm performs exactly โŒŠn/2โŒ‹ swaps where n is the array length, achieving O(n) time complexity with O(1) space complexity since we only use two extra variables regardless of input size.

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with a small example: s = ['c', 'a', 't']

Initial Setup:

  • Array: ['c', 'a', 't']
  • i = 0 (pointing to 'c')
  • j = 2 (pointing to 't')

Step 1: First swap

  • Check condition: i < j? Yes (0 < 2), so continue
  • Swap s[0] with s[2]: ['c', 'a', 't'] becomes ['t', 'a', 'c']
  • Update pointers: i = 1, j = 1

Step 2: Check termination

  • Check condition: i < j? No (1 is not less than 1)
  • Exit the loop

Final Result: ['t', 'a', 'c']

The string "cat" has been successfully reversed to "tac" using only 1 swap operation. Notice how the middle character 'a' stayed in its position, which is correct for odd-length arrays. The algorithm used only two integer variables (i and j) for the entire process, maintaining O(1) space complexity.

Solution Implementation

1class Solution:
2    def reverseString(self, s: List[str]) -> None:
3        """
4        Reverses a string in-place using two-pointer technique.
5      
6        Args:
7            s: List of characters representing the string to be reversed
8      
9        Returns:
10            None (modifies the list in-place)
11        """
12        # Initialize two pointers: left pointer at start, right pointer at end
13        left = 0
14        right = len(s) - 1
15      
16        # Continue swapping until pointers meet in the middle
17        while left < right:
18            # Swap characters at left and right positions
19            s[left], s[right] = s[right], s[left]
20          
21            # Move pointers towards the center
22            left += 1
23            right -= 1
24
1class Solution {
2    /**
3     * Reverses the input character array in-place using two-pointer technique.
4     * Time Complexity: O(n), where n is the length of the array
5     * Space Complexity: O(1), as we only use constant extra space
6     * 
7     * @param s The character array to be reversed in-place
8     */
9    public void reverseString(char[] s) {
10        // Initialize two pointers: left starting from beginning, right from end
11        int left = 0;
12        int right = s.length - 1;
13      
14        // Continue swapping until the pointers meet in the middle
15        while (left < right) {
16            // Swap characters at left and right positions
17            char temp = s[left];
18            s[left] = s[right];
19            s[right] = temp;
20          
21            // Move pointers towards the center
22            left++;
23            right--;
24        }
25    }
26}
27
1class Solution {
2public:
3    /**
4     * Reverses a string in-place using two-pointer technique
5     * @param s - vector of characters to be reversed in-place
6     */
7    void reverseString(vector<char>& s) {
8        // Initialize two pointers: left starting from beginning, right from end
9        int left = 0;
10        int right = s.size() - 1;
11      
12        // Continue swapping until pointers meet in the middle
13        while (left < right) {
14            // Swap characters at left and right positions
15            swap(s[left], s[right]);
16          
17            // Move left pointer forward and right pointer backward
18            left++;
19            right--;
20        }
21    }
22};
23
1/**
2 * Reverses a string array in-place using two-pointer technique.
3 * Do not return anything, modify s in-place instead.
4 * @param s - The character array to be reversed
5 */
6function reverseString(s: string[]): void {
7    // Initialize two pointers: left pointer at start, right pointer at end
8    let leftIndex: number = 0;
9    let rightIndex: number = s.length - 1;
10  
11    // Continue swapping until the pointers meet in the middle
12    while (leftIndex < rightIndex) {
13        // Swap characters at left and right positions using destructuring
14        [s[leftIndex], s[rightIndex]] = [s[rightIndex], s[leftIndex]];
15      
16        // Move left pointer forward and right pointer backward
17        leftIndex++;
18        rightIndex--;
19    }
20}
21

Time and Space Complexity

The time complexity is O(n), where n is the length of the array. The algorithm uses a two-pointer approach that traverses from both ends of the array toward the center. Each element is visited exactly once - the loop runs for n/2 iterations, and in each iteration, we perform a constant-time swap operation. Therefore, the total time complexity is O(n/2) which simplifies to O(n).

The space complexity is O(1). The algorithm only uses two integer variables i and j as pointers to track positions in the array, regardless of the input size. The swapping operation is done in-place without requiring any additional data structures that scale with the input size. The space used remains constant throughout the execution.

Common Pitfalls

1. Attempting to return the modified array

A frequent mistake is adding a return statement at the end of the function, which violates the problem requirements. The function signature specifies -> None, meaning it should modify the array in-place without returning anything.

Incorrect approach:

def reverseString(self, s: List[str]) -> None:
    left = 0
    right = len(s) - 1
    while left < right:
        s[left], s[right] = s[right], s[left]
        left += 1
        right -= 1
    return s  # โŒ Wrong - should not return anything

Solution: Simply omit the return statement and let the function end naturally.

2. Using wrong loop condition (<= instead of <)

Using while left <= right instead of while left < right causes unnecessary operations. When the pointers meet at the same index, swapping an element with itself is redundant.

Incorrect approach:

while left <= right:  # โŒ Unnecessary swap when left == right
    s[left], s[right] = s[right], s[left]
    left += 1
    right -= 1

Solution: Use while left < right to stop when pointers meet or cross, avoiding pointless swaps.

3. Creating a new array instead of modifying in-place

Some might instinctively create a reversed copy and then try to assign it back, which violates the O(1) space requirement.

Incorrect approach:

def reverseString(self, s: List[str]) -> None:
    reversed_s = s[::-1]  # โŒ Creates O(n) extra space
    for i in range(len(s)):
        s[i] = reversed_s[i]

Solution: Stick to the two-pointer approach that swaps elements directly within the original array.

4. Forgetting to handle empty arrays or single characters

While the two-pointer approach naturally handles these edge cases (the while loop simply doesn't execute), explicitly checking for them can cause unnecessary code complexity or errors.

Overcomplicated approach:

def reverseString(self, s: List[str]) -> None:
    if len(s) <= 1:  # Unnecessary check
        return
    left = 0
    right = len(s) - 1
    # ... rest of the code

Solution: The standard two-pointer implementation already handles empty arrays and single characters correctly without special cases. For an empty array or single character, left < right is false from the start, so no swaps occur.

Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which of these properties could exist for a graph but not a tree?


Recommended Readings

Want a Structured Path to Master System Design Too? Donโ€™t Miss This!

Load More