Introduction
Welcome to the first lesson of your algorithm refresher course! We'll begin with a foundational pattern that appears in many LeetCode problems: in-place array and string manipulation. Today's goal is to master the two-pointer technique for reversing a sequence, like an array or string, without allocating any significant extra memory. This is a core skill tested in problems like LeetCode 344 ("Reverse String"), and the two-pointer pattern itself is a versatile tool you'll use in many other algorithms.
Since your goal is to quickly get up to speed for technical interviews, we'll focus directly on the optimal implementation, its performance characteristics, and common pitfalls, particularly those relevant to Python.
The "In-Place" Constraint: O(1) Space
A common requirement in algorithm problems is to perform an operation "in-place," which means modifying the given data structure directly rather than creating a new one. This is a constraint on space complexity, typically requiring it to be O(1), or constant space.
In Python, it's easy to reverse a list with slicing: new_list = old_list[::-1]. However, this operation creates a new, reversed copy of the list, consuming O(N) extra space, where N is the number of elements. This violates the in-place requirement.
The problem requires us to alter the original memory block of the array. To do this efficiently, we'll use a classic method: the two-pointer approach.
Reverse String - Leetcode 344 - 2 Pointers - (Python)
For a clear explanation of what "in-place" means in this context and why simple slicing isn't a valid solution, watch the beginning of this video from the Greg Hogg channel.
The relevant discussion is in the first part of the video, from the start until the introduction of the two-pointer approach.
The Two-Pointer Algorithm for Reversal
The intuition behind in-place reversal is symmetrical swapping. The first element needs to be swapped with the last, the second with the second-to-last, and so on, until we reach the middle of the array.
We can manage this process cleanly with two pointers (which, in Python, are just integer indices):
- Initialize a
leftpointer at the start of the array (index 0). - Initialize a
rightpointer at the end of the array (indexlen(s) - 1). - In a loop, as long as
leftis less thanright:
a. Swap the elements at theleftandrightindices.
b. Move theleftpointer one step to the right (left += 1).
c. Move therightpointer one step to the left (right -= 1).
The loop terminates when the pointers meet or cross, at which point the array is fully reversed.
This diagram illustrates the process for both even and odd-length arrays. Notice how for an odd-length array, the middle element naturally stays in its correct place without needing to be swapped.

To solidify this logic, please read through a detailed explanation of the approach.
344. Reverse String - In-Depth Explanation
This article from AlgoMonster provides a step-by-step breakdown of the two-pointer technique.
Focus on the sections titled Intuition and Solution Approach. The step-by-step example with ['h', 'e', 'l', 'l', 'o'] is particularly helpful for visualizing the pointer movements and swaps.
Python Implementation
With your background, the implementation should be straightforward. Python's tuple assignment syntax makes the swap operation particularly clean, avoiding the need for an explicit temporary variable.
Here is a typical implementation for LeetCode 344, which expects the List[str] to be modified in-place.
from typing import List
def reverseString(s: List[str]) -> None:
"""
Reverses a list of characters in-place using the two-pointer technique.
Does not return anything, modifies s directly.
"""
left = 0
right = len(s) - 1
while left < right:
# Pythonic swap using tuple unpacking
s[left], s[right] = s[right], s[left]
# Move pointers towards the center
left += 1
right -= 1
# Example usage:
my_string = ['h', 'e', 'l', 'l', 'o']
reverseString(my_string)
print(my_string) # Output: ['o', 'l', 'l', 'e', 'h']
another_string = ['H', 'a', 'n', 'n', 'a', 'h']
reverseString(another_string)
print(another_string) # Output: ['h', 'a', 'n', 'n', 'a', 'H']
Loop Condition: while left < right
It's important to use < and not <=. If the list has an odd number of elements, the pointers will eventually meet at the middle element (left == right). A swap at this point (s[left], s[left] = s[left], s[left]) is redundant. Using < correctly stops the loop as soon as the pointers meet or cross.
Complexity Analysis
Understanding the performance of this algorithm is crucial for interviews.
-
Time Complexity: O(N)
The algorithm makes approximately N/2 swaps. Since we analyze complexity in terms of the input size N, this linear relationship results in a time complexity of O(N). Each element is touched and swapped at most once. -
Space Complexity: O(1)
This is the key advantage of the in-place approach. We only use two integer variables (leftandright) to store the indices. The amount of memory used does not grow with the size of the input array, so the space complexity is constant, or O(1).
The following video provides a concise walkthrough of the code and reinforces the complexity analysis.
Reverse String - Leetcode 344 - 2 Pointers - (Python)
Watch the remainder of the Greg Hogg video for a code walkthrough and complexity discussion.
Focus on the code implementation and the final complexity analysis.
Conclusion
In this lesson, we've refreshed a fundamental algorithm for in-place array reversal. You should now be comfortable implementing this pattern and explaining its efficiency.
Here are the key takeaways:
- In-place modification means altering the original data structure with O(1) extra space.
- Python's
s[::-1]creates a new object and is not an in-place solution. - The two-pointer technique is the standard, efficient method for in-place reversal. It works by swapping elements from both ends of the array and moving the pointers toward the center.
- The algorithm has a time complexity of O(N) and a space complexity of O(1).
This pattern is a building block. In the next lesson, we will extend this concept to solve a slightly more complex problem: reversing specific or alternating segments of an array, which requires applying the same two-pointer logic to sub-arrays.