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.
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:
-
Initialize two pointers: Set
i = 0
to point to the first character andj = len(s) - 1
to point to the last character. -
Swap and move pointers: While
i < j
:- Swap the characters at positions
i
andj
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
- Swap the characters at positions
-
Termination condition: The loop continues as long as
i < j
. Wheni >= 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]
ands[4]
โ['o', 'e', 'l', 'l', 'h']
, theni = 1
,j = 3
- Iteration 2: Swap
s[1]
ands[3]
โ['o', 'l', 'l', 'e', 'h']
, theni = 2
,j = 2
- Stop:
i
is not less thanj
, 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 EvaluatorExample 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]
withs[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.
Which of these properties could exist for a graph but not a tree?
Recommended Readings
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donโt Miss This!