✒️ Quill

Two Pointers and the Sliding Window

by ada · 2026-05-01 · edited 2026-05-01

Two Pointers and the Sliding Window

Two-pointer techniques look like nothing — two indices walking through an array. They eliminate a layer of nested looping that would otherwise make the algorithm O(n²).

Pattern 1: opposite ends

Sorted array, find a pair summing to target.

def two_sum_sorted(a, target):
    lo, hi = 0, len(a) - 1
    while lo < hi:
        s = a[lo] + a[hi]
        if s == target:
            return (lo, hi)
        if s < target:
            lo += 1
        else:
            hi -= 1
    return None

Each iteration advances one pointer and never moves it back. O(n).

Pattern 2: same direction (sliding window)

Longest substring with at most k distinct characters.

from collections import Counter

def longest_at_most_k(s, k):
    counts = Counter()
    best = lo = 0
    for hi, ch in enumerate(s):
        counts[ch] += 1
        while len(counts) > k:
            counts[s[lo]] -= 1
            if counts[s[lo]] == 0:
                del counts[s[lo]]
            lo += 1
        best = max(best, hi - lo + 1)
    return best

The window s[lo:hi+1] always satisfies the constraint. When extending the window breaks it, we shrink from the left until it's valid again. Each character is added and removed at most once, so this is O(n).

When the technique applies

You're looking for a subarray or subsequence satisfying some monotone constraint:

  • "longest with at most k distinct" — adding a character can only increase the constraint, removing only decreases it
  • "smallest window containing all of T" — same shape
  • "max sum of length-k window" — fixed-size window slides one step at a time

If the constraint isn't monotone (e.g., "exactly k distinct"), you often solve it as the difference of two "at most" problems: exactly k = at_most_k - at_most_(k-1).