Module 10: Intervals & Greedy Algorithms·Tutorial 17 of 23 (Step 10.2)
All Tutorials·DSA Roadmap·2 Problems · ~6 hrs

10.2 Greedy Algorithms

Understand what a Greedy Algorithm is, when making the best local choice guarantees the global best answer, and when you must use DP instead.

01 Read the story: What & Why
02 Follow the drawing: Visual stepper
03 Practice code: 4 languages + problems

1. What Is a Greedy Algorithm?

A Greedy Algorithm solves an optimization problem step-by-step by always picking the choice that looks best right now (the locally optimal choice) and never undoing or reconsidering past choices.

Visual: Greedy Farthest Reach Boundary (Jump Game: farthest = max(farthest, i + nums[i]))
nums[0]=20+2=2nums[1]=31+3=4 ★nums[2]=12+1=3nums[3]=13+1=4nums[4]=4Goal!Index 1 jumps up to index 4 — expanding our single contiguous reachable frontier in O(N)!

2. Why Do We Need Greedy & When Does It Work vs. Fail?

Why Greedy Is Amazing When It Works

Backtracking explores an exponential tree (O(2^N)), and Dynamic Programming builds a table of subproblems (O(N^2)). When a problem has the Greedy Choice Property (meaning taking the best immediate step never locks you out of the best overall outcome), Greedy solves it in one O(N) pass with O(1) memory!

How to Tell Greedy vs. Dynamic Programming Apart

  • Where Greedy Works (Jump Game): You stand at index 0 and each nums[i] tells you the maximum jump length from i. Why explore every jump combination? If you can reach index farthest, you can also reach every single index before farthest! So tracking a single variable farthest = max(farthest, i + nums[i]) is 100% sufficient.
  • Where Greedy Fails (Coin Change with [1, 3, 4], target 6): Greedy grabs the biggest coin (4), forcing 4 + 1 + 1 (3 coins), whereas 3 + 3 uses only 2 coins! Whenever a greedy choice today can hurt you tomorrow, use Dynamic Programming instead.

Quick Decision Table: Should I Use Greedy or Dynamic Programming?

Signal in the ProblemGreedy (O(N) or O(N log N))Dynamic Programming (O(N^2) or O(N * W))
Can items be split or ordered monotonically?Yes (Fractional Knapsack, Activity Selection, Jump Reach)No (0/1 Discrete Knapsack, Arbitrary Coin Denominations)
Does a local best choice ever block a better future combo?Never (further jump reach always covers shorter reach)Yes (picking a large coin or house today blocks adjacent/better sums)
Warm-Up Example: Assign Cookies (greed = [1,2,3], cookies = [1,1])Sort both arrays and give the smallest cookie that satisfies the least greedy child!Not needed — giving a bigger cookie than necessary never helps another child more.
The Hand-Drawn Step-by-Step Walkthrough
Step 1 / 1

Interactive Step-by-Step Trace: Greedy Farthest Reach (Jump Game)

Can we reach the last index in nums = [2, 3, 1, 1, 4]?

Step 1: Index 0 (val=2) sets farthest = 2; Index 1 (val=3) extends to 4!
reach 0+2=22
reach 1+3=4!3farthest=4
idx 21
idx 31
idx 4 (Goal)4Reached!
farthest = max(farthest, i + nums[i]) -> max(2, 1 + 3) = 4 >= last_idx!

As soon as farthest >= 4, we know the end is reachable in O(N) time and O(1) space!

✎ Remember this: If at any index i > farthest, you are stranded in a zero-trap—return False.

3. Basic Operations & Walkthroughs (All 4 Languages)

# 1. Jump Game: Track the furthest index reachable so far -> O(N) time, O(1) space
def can_jump(nums: list[int]) -> bool:
  farthest = 0
  for i, jump in enumerate(nums):
      if i > farthest:
          return False  # We landed on an unreachable gap!
      farthest = max(farthest, i + jump)
  return True

# 2. Gas Station: Reset starting station whenever tank drops below 0 -> O(N)
def can_complete_circuit(gas: list[int], cost: list[int]) -> int:
  if sum(gas) < sum(cost):
      return -1  # Total fuel < total cost -> impossible!
  tank = start = 0
  for i in range(len(gas)):
      tank += gas[i] - cost[i]
      if tank < 0:
          start = i + 1
          tank = 0
  return start

4. Core Interview Patterns & Common Traps

Pattern: Jump Game II (BFS-Style Greedy Level Window [l..r])

Use when finding the MINIMUM number of jumps to reach the end of an array in O(N) time and O(1) space.

jumps = 0
cur_end = farthest = 0
for i in range(len(nums) - 1):
  farthest = max(farthest, i + nums[i])
  if i == cur_end:        # Finished scanning current jump's reach!
      jumps += 1
      cur_end = farthest  # Commit to the furthest reach for next jump
return jumps
Operation / PatternTimeSpaceNotes
Greedy Reachability / Surplus ScanO(N)O(1)Single pass maintaining running boundary or surplus

5. Practice On Your Own (Curated Submodule Problems)

0 / 2 Solved
StatusProblemDifficultyComplexityHint?Links & Notes
Jump Game
Local Greedy Reachability (Jump Game)
Medium
T: O(N)
S: O(1)
Solve
Gas Station
Local Greedy Reachability (Jump Game)
Medium
T: O(N)
S: O(1)
Solve