Courses › Coding Interviews › Patterns

Two Pointers

Opposite-end and fast/slow pointers on sorted arrays and linked lists.

Two pointers walk through a sequence together, letting you process pairs or partitions in a single O(n) pass instead of nested loops. The trick is knowing which pointer to move, and why that move never skips the answer.

When to use it

  • The input is sorted (or sorting it doesn't break the problem) and you're looking for pairs or triplets
  • You need to compare elements from both ends — palindromes, container problems
  • You need to partition or compact an array in place — remove duplicates, move zeros
  • Linked lists: finding the middle, detecting cycles, the k-th node from the end

Variant 1: opposite ends

def pair_sum_sorted(nums, target):
    lo, hi = 0, len(nums) - 1
    while lo < hi:
        s = nums[lo] + nums[hi]
        if s == target:
            return [lo, hi]
        if s < target:
            lo += 1   # need a bigger sum
        else:
            hi -= 1   # need a smaller sum
    return []

Why it's correct: if nums[lo] + nums[hi] is too small, nums[lo] can't pair with anything (nums[hi] is already the largest remaining), so it's safe to discard.

3Sum: sort, fix one element, then run the two-pointer pair search on the rest — O(n²) instead of O(n³). Skip duplicate values to avoid duplicate triplets.

Variant 2: same direction (read/write)

def remove_duplicates(nums):
    write = 0
    for read in range(len(nums)):
        if read == 0 or nums[read] != nums[read - 1]:
            nums[write] = nums[read]
            write += 1
    return write

Variant 3: fast and slow pointers

def has_cycle(head):
    slow = fast = head
    while fast and fast.next:
        slow, fast = slow.next, fast.next.next
        if slow is fast:
            return True
    return False

The same idea finds the middle of a list (when fast reaches the end, slow is in the middle) and the start of a cycle.

Pitfalls

  • Moving the wrong pointer — always justify the move by what it rules out
  • Forgetting to skip duplicates in 3Sum
  • while lo < hi vs lo <= hi — decide whether a single element can be its own pair

[!TIP] Practice Trapping Rain Water — the two-pointer version is the elegant O(1)-space solution.