Skip to content

Lesson 9 of 9 · 18m

Greedy and Two-Pointer Patterns

The patterns that solve a surprising number of problems — greedy choice, two pointers on sorted data, sliding windows — and when each applies.

Most interview-style problems aren't about knowing a specific algorithm — they're about recognizing a pattern. Three patterns cover a surprising share.

Two pointers on sorted data

def two_sum_sorted(nums, target):
    l, r = 0, len(nums) - 1
    while l < r:
        s = nums[l] + nums[r]
        if s == target: return l, r
        if s < target: l += 1     # too small — need bigger left
        else: r -= 1              # too big — need smaller right

On sorted data, one pointer at each end converges in O(n) — no hash map needed. Same idea: palindrome check, "closest pair," container-with-most-water.

Sliding window

def longest_no_repeat(s):
    seen, left, best = {}, 0, 0
    for right, c in enumerate(s):
        if c in seen and seen[c] >= left:
            left = seen[c] + 1    # shrink window
        seen[c] = right
        best = max(best, right - left + 1)
    return best

"Longest substring with no repeats," "max sum of k consecutive," "min window substring" — all sliding window: expand right, shrink left when the invariant breaks.

Greedy: take the locally optimal

When a problem's optimal solution is built from locally-optimal choices, a greedy algorithm works — always take the best immediate move and never look back.

# activity selection: always pick the earliest-ending compatible activity
def max_activities(intervals):
    intervals.sort(key=lambda x: x[1])
    count, end = 0, 0
    for s, e in intervals:
        if s >= end:
            count += 1
            end = e
    return count

Greedy works when a problem has the "greedy choice property" — a local optimum leads to global optimum. When it doesn't (most interesting problems), DP or a smarter structure is the answer.

Field notes

  • Recognize the pattern by the constraints: sorted input → two pointers; contiguous subarray → sliding window; "maximize count with non-overlap" → greedy.
  • A greedy solution is fast and wrong if the problem doesn't have the property — test on the edge cases before trusting it.