2.1 Two Pointers
Understand what a Pointer index is, why Two Pointers eliminates O(N^2) nested loops using O(1) memory, and master opposite-end, read/write, and 3-way pointers.
1. What Is the Two Pointers Technique?
In array problems, a "pointer" is simply an integer variable (like left = 0 or right = n - 1) that remembers a position in the array.
Instead of using a single loop variable i (which only looks at one spot at a time) or two nested loops for i ... for j ... (which blindly checks every pair in O(N^2) time), Two Pointers places two coordinated bookmarks in the array and moves them using a smart rule so each element is visited at most once (O(N) time) with O(1) extra space.
2. Why Do We Need Two Pointers & How Do the 3 Flavors Work?
Flavor 1: Opposite-End Pointers (left = 0, right = n - 1)
Suppose you have a sorted list [2, 5, 8, 12, 30, 45] and want two numbers that add up to 35.
If you stand at left = 0 (2) and right = 5 (45):
2 + 45 = 47(too big!). Since2is already the smallest number in the list,45added to anything else will be even bigger than47. We can permanently cross out45(right -= 1)!- Now
2 + 30 = 32(too small!). Since30is the largest remaining number,2is too small for everything else. Cross out2(left += 1)! - Now
5 + 30 = 35— found in 3 steps instead ofN^2!
Flavor 2: Same-Direction Read / Write Pointers (write = 0, read = 0)
When you need to filter or compact an array in-place (like removing duplicates or moving zeroes to the end), calling nums.pop(i) shifts the whole array (O(N^2)).
Instead, read scans every element while write marks the next clean slot. Whenever read finds a keeper, copy nums[read] to nums[write] and step write += 1.
Flavor 3: Three-Way Partitioning (low, mid, high)
When sorting an array with only 3 distinct values (0, 1, 2 in Sort Colors), keep 0s before low, 1s between low and mid, and 2s after high.
Step Through the Visual Drawing: Converging Two Pointers
Click Next below to see why moving left++ or right-- eliminates an entire row of pairs in O(1) time:
Interactive Step-by-Step Trace: Sorted Two Sum with Converging Pointers
Find two numbers in sorted [1, 3, 4, 6, 9] that sum to Target = 9:
Since 1 + 9 is already > 9, 9 + anything larger than 1 is also > 9. Eliminate 9!
3. Basic Operations & Walkthroughs (All 4 Languages)
# 1. Opposite-End Pointers: Valid Palindrome / Sorted Two-Sum
def two_sum_sorted(nums: list[int], target: int) -> list[int]:
left, right = 0, len(nums) - 1
while left < right:
s = nums[left] + nums[right]
if s == target:
return [left + 1, right + 1]
elif s < target:
left += 1
else:
right -= 1
return []
# 2. Same-Direction Read/Write: Remove Duplicates from Sorted Array
def remove_duplicates(nums: list[int]) -> int:
write = 1
for read in range(1, len(nums)):
if nums[read] != nums[write - 1]:
nums[write] = nums[read]
write += 1
return write
# 3. Three-Way Partitioning (Sort Colors 0, 1, 2)
def sort_colors(nums: list[int]) -> None:
low, mid, high = 0, 0, len(nums) - 1
while mid <= high:
if nums[mid] == 0:
nums[low], nums[mid] = nums[mid], nums[low]
low += 1; mid += 1
elif nums[mid] == 1:
mid += 1
else:
nums[mid], nums[high] = nums[high], nums[mid]
high -= 14. Core Interview Patterns & Common Traps
Use when searching for pairs/triplets in sorted data or optimizing a width * min(height) objective from outer boundaries inward.
nums.sort()
for i in range(len(nums) - 2):
if i > 0 and nums[i] == nums[i - 1]:
continue # Skip duplicate anchor
l, r = i + 1, len(nums) - 1
while l < r:
s = nums[i] + nums[l] + nums[r]
if s == 0:
res.append([nums[i], nums[l], nums[r]])
l += 1; r -= 1
while l < r and nums[l] == nums[l - 1]: l += 1
elif s < 0: l += 1
else: r -= 1| Operation / Pattern | Time | Space | Notes |
|---|---|---|---|
| Opposite-End Pointers (Already Sorted) | O(N) | O(1) | Each step moves L right or R left |
| 3Sum (Sort + Fix i + Two Pointers) | O(N^2) | O(1) aux | Skip duplicate values of i, L, and R |
| Read / Write In-Place Compaction | O(N) | O(1) | Preserves relative order of kept elements |
| Dutch National Flag (3-Way Partition) | O(N) | O(1) | Single pass; do not advance mid when swapping with high |
5. Practice On Your Own (Curated Submodule Problems)
| Status | Problem | Difficulty | Complexity | Hint? | Links & Notes |
|---|---|---|---|---|---|
Valid Palindrome Opposite-End Converging Pointers | Easy | T: O(N) S: O(1) | |||
Two Sum II - Input Array Is Sorted Opposite-End Converging Pointers | Medium | T: O(N) S: O(1) | |||
3Sum Opposite-End Converging Pointers | Medium | T: O(N^2) S: O(1) aux | |||
4Sum Opposite-End Converging Pointers | Medium | T: O(N^3) S: O(1) aux | |||
Container With Most Water Opposite-End Converging Pointers | Medium | T: O(N) S: O(1) | |||
Trapping Rain Water Opposite-End Converging Pointers | Hard | T: O(N) S: O(1) | |||
Squares of a Sorted Array Opposite-End Converging Pointers | Easy | T: O(N) S: O(N) | |||
Valid Palindrome II Opposite-End Converging Pointers | Easy | T: O(N) S: O(1) | |||
Boats to Save People Opposite-End Converging Pointers | Medium | T: O(N log N) S: O(1) | |||
Remove Duplicates from Sorted Array Same-Direction Read/Write Pointers | Easy | T: O(N) S: O(1) | |||
Remove Duplicates from Sorted Array II Same-Direction Read/Write Pointers | Medium | T: O(N) S: O(1) | |||
Move Zeroes Same-Direction Read/Write Pointers | Easy | T: O(N) S: O(1) | |||
Merge Sorted Array Same-Direction Read/Write Pointers | Easy | T: O(M + N) S: O(1) | |||
Is Subsequence Same-Direction Read/Write Pointers | Easy | T: O(N) S: O(1) | |||
Sort Colors Three-Way Partitioning (Dutch National Flag) | Medium | T: O(N) S: O(1) | |||
Next Permutation Three-Way Partitioning (Dutch National Flag) | Medium | T: O(N) S: O(1) | |||
Rearrange Array Elements by Sign Three-Way Partitioning (Dutch National Flag) | Medium | T: O(N) S: O(N) | |||
Rotate Array Three-Way Partitioning (Dutch National Flag) | Medium | T: O(N) S: O(1) |