Greedy Algorithms
π At a Glance
| Aspect | Details |
|---|---|
| Time to Read | 35 minutes |
| Prerequisites | Part 1 (Algorithm Analysis), Part 16 (DP basics) |
| Key Concepts | Greedy Choice, Activity Selection, Huffman, Scheduling |
| Difficulty | βββ (Intermediate) |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β GREEDY ALGORITHMS β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β β β THE GREEDY APPROACH β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β β β β β At each step, make the locally optimal choice β β β β Hope it leads to globally optimal solution β β β β β β β β βββββββ βββββββ βββββββ βββββββ β β β β βStartββββββBest ββββββBest ββββββGoal β β β β β β β βlocalβ βlocalβ β β β β β β βββββββ βββββββ βββββββ βββββββ β β β β β β β βWorks when: Greedy choice property + Optimal substructureβ β β β β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β β CLASSIC PROBLEMS β β βββββββββββββββββββ βββββββββββββββββββ β β β Activity Select β β Huffman Coding β β β β βββββββββββββββ β β βββββββββββββββ β β β β Max activities β β Optimal prefix β β β β without overlap β β codes β β β βββββββββββββββββββ βββββββββββββββββββ β β β β βββββββββββββββββββ βββββββββββββββββββ β β β Fractional β β Job Scheduling β β β β Knapsack β β βββββββββββββββ β β β β βββββββββββββββ β β Minimize β β β β Max value with β β penalties β β β β fractions β β β β β βββββββββββββββββββ βββββββββββββββββββ β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π― What You'll Learn
After completing this article, you will be able to:
- Identify greedy problems: Recognize when greedy works
- Prove correctness: Exchange argument and greedy stays ahead
- Solve classic problems: Activity selection, Huffman, scheduling
- Avoid pitfalls: Know when greedy fails
π₯ Production Story: The Task Scheduler Optimization
A cloud platform needed to schedule thousands of tasks to minimize total completion time.
The Problem
JAVA(10 lines)CodeLoading syntax highlighter...
The Solution: Shortest Job First
JAVA(30 lines)CodeLoading syntax highlighter...
Why It Works (Exchange Argument)
If tasks aren't in SJF order, we can improve by swapping adjacent jobs: Before swap: [..., A, B, ...] where duration(A) > duration(B) A completes at time t B completes at time t + duration(B) After swap: [..., B, A, ...] B completes at time t - duration(A) + duration(B) = t' A completes at time t Since duration(B) < duration(A): - B's completion time decreased - A's completion time stayed same - Total improved! Therefore, SJF order is optimal.
π§ Mental Model: The Greedy Framework
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β GREEDY ALGORITHM FRAMEWORK β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β β β STEP 1: Identify the greedy choice β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β What's the "best" item to pick first? β β β β - Largest? Smallest? Earliest finish? Best ratio? β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β β STEP 2: Prove greedy choice is safe β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β Show: There exists an optimal solution that includes β β β β our greedy choice β β β β β β β β Methods: β β β β - Exchange argument β β β β - Greedy stays ahead β β β β - Structural argument β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β β STEP 3: Prove optimal substructure β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β After making greedy choice, remaining problem is β β β β smaller instance of same problem β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π¬ Deep Dive: Activity Selection
The Problem
Given activities with start and end times, select maximum non-overlapping activities.
JAVA(18 lines)CodeLoading syntax highlighter...
Why Earliest Finish First Works
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β ACTIVITY SELECTION PROOF β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β β β Claim: Greedy choice (earliest finish) is always safe β β β β Proof by exchange: β β Let OPT be any optimal solution β β Let aβ be the activity with earliest finish time β β Let a_first be the first activity in OPT β β β β If aβ = a_first: Done! Greedy matches OPT β β β β If aβ β a_first: β β - aβ finishes no later than a_first (earliest finish) β β - Replace a_first with aβ in OPT β β - No new conflicts (aβ ends earlier) β β - Same size, still valid β OPT' is optimal with aβ β β β β Timeline: β β aβ: |-----| β β a_first:|--------| β β next: |-----| β β β β Swapping a_first β aβ can only add more room for next β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Weighted Activity Selection
When activities have weights, greedy doesn't work - need DP:
JAVA(35 lines)CodeLoading syntax highlighter...
π¬ Deep Dive: Huffman Coding
The Problem
Create optimal prefix-free codes for data compression.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β HUFFMAN CODING β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β β β Characters: a(45%), b(13%), c(12%), d(16%), e(9%), f(5%) β β β β Fixed-length: 3 bits each β 3 Γ 100 = 300 bits β β β β Huffman tree: β β (100) β β / \ β β (55) a(45) β β / \ 0 β β (25) (30) β β / \ / \ β β c(12) b(13) d(16) (14) β β 100 101 110 / \ β β f(5) e(9) β β 1110 1111 β β β β Huffman: 1Γ45 + 3Γ13 + 3Γ12 + 3Γ16 + 4Γ9 + 4Γ5 = 224 bits β β Savings: 25% β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Implementation
JAVA(87 lines)CodeLoading syntax highlighter...
Why Huffman is Optimal
Greedy choice: Always merge two nodes with smallest frequencies Proof idea: 1. Optimal tree exists where two lowest-frequency symbols are siblings at the deepest level (exchange argument) 2. After merging, we have smaller instance of same problem (one fewer symbol, combined frequency) 3. Recursively optimal β globally optimal
π¬ Deep Dive: Fractional Knapsack
The Problem
Unlike 0/1 knapsack, we can take fractions of items.
JAVA(36 lines)CodeLoading syntax highlighter...
Comparison with 0/1 Knapsack
Items: weights = [10, 20, 30], values = [60, 100, 120], capacity = 50 Ratios: 60/10=6, 100/20=5, 120/30=4 Fractional (greedy): - Take all of item 1: value=60, remaining=40 - Take all of item 2: value=60+100=160, remaining=20 - Take 20/30 of item 3: value=160+120Γ(20/30)=240 0/1 (DP needed): - Take items 2 and 3: value=100+120=220 Greedy gives 240 for fractional, but would give wrong answer for 0/1!
π¬ Deep Dive: Job Scheduling
Minimizing Lateness
JAVA(24 lines)CodeLoading syntax highlighter...
Job Scheduling with Profits and Deadlines
JAVA(71 lines)CodeLoading syntax highlighter...
π¬ Deep Dive: When Greedy Fails
Coin Change Problem
JAVA(19 lines)CodeLoading syntax highlighter...
The Key Difference
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β GREEDY vs DYNAMIC PROGRAMMING β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β β β GREEDY β β βββββββ β β - Makes one choice at each step β β - Never reconsiders choices β β - Works when: greedy choice property holds β β - Time: Usually O(n) or O(n log n) β β β β DYNAMIC PROGRAMMING β β ββββββββββββββββββββ β β - Considers all choices at each step β β - Stores results for future use β β - Works when: optimal substructure only β β - Time: Usually O(nΒ²) or O(nΓk) β β β β Rule of thumb: β β βββββββββββββββ β β 1. Try greedy first (simpler, faster) β β 2. Find counterexample β use DP β β 3. Prove greedy works β keep greedy β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β οΈ Common Mistakes
Mistake 1: Assuming Greedy Always Works
JAVA(10 lines)CodeLoading syntax highlighter...
Mistake 2: Wrong Greedy Criterion
JAVA(5 lines)CodeLoading syntax highlighter...
Mistake 3: Not Handling Ties Properly
JAVA(16 lines)CodeLoading syntax highlighter...
π Debug This: Activity Selection Bug
This activity selection has a bug. Can you find it?
JAVA(16 lines)CodeLoading syntax highlighter...
π Click to reveal the bug
JAVA(5 lines)CodeLoading syntax highlighter...
Activities: [0,10], [1,3], [3,5], [5,7], [7,9] Shortest duration first: [1,3] (len 2), [3,5] (len 2), [5,7] (len 2), [7,9] (len 2), [0,10] (len 10) Result: [1,3], [3,5], [5,7], [7,9] = 4 activities β But consider: [0,2], [1,10], [2,3] Shortest first: [0,2] (len 2), [2,3] (len 1), [1,10] (len 9) Order: [2,3], [0,2], [1,10] Result: [2,3] (can't add [0,2] - overlaps!) = 1 activity Earliest finish: [0,2], [2,3], [1,10] Result: [0,2], [2,3] = 2 activities β
π» Exercises
Exercise 1: Assign Mice to Holes ββ
N mice and N holes on a line. Find minimum time for all mice to reach holes (each mouse to one hole).
JAVA(3 lines)CodeLoading syntax highlighter...
Exercise 2: Minimum Platforms ββ
Given arrival and departure times of trains, find minimum platforms needed.
JAVA(3 lines)CodeLoading syntax highlighter...
Exercise 3: Gas Station βββ
N gas stations in a circle. Find starting station to complete the circuit.
JAVA(3 lines)CodeLoading syntax highlighter...
Exercise 4: Jump Game II βββ
Minimum jumps to reach end. Each position has max jump length.
JAVA(3 lines)CodeLoading syntax highlighter...
Exercise 5: Meeting Rooms III ββββ
Given n rooms and meetings, find which room held most meetings. Meetings go to lowest numbered available room.
JAVA(3 lines)CodeLoading syntax highlighter...
π€ Interview Questions
Q1: "How do you prove a greedy algorithm is correct?"
- Take any optimal solution OPT
- Show we can transform it to match greedy without worsening
- Usually swap elements to show greedy choice is at least as good
- Define a measure of progress
- Show greedy solution is always at least as good as any other
- By induction: if greedy is ahead at step k, it stays ahead at step k+1
Exchange: If OPT's first activity isn't earliest-finish, swap it with earliest-finish activity. Result: same or fewer conflicts. Stays ahead: At each step, greedy has at least as many activities AND ends no later than any other solution with same number of activities.
Q2: "When should I try greedy vs DP?"
- Problem has "optimal substructure"
- Local choices seem to lead to global optimum
- You can identify a clear greedy criterion
- Greedy counterexample exists
- Need to consider multiple choices
- Problem has overlapping subproblems
- Propose greedy strategy
- Try to find counterexample
- If found β use DP
- If not β try to prove greedy works
Q3: "Implement interval scheduling with weights."
JAVA(30 lines)CodeLoading syntax highlighter...
Key insight: Greedy doesn't work with weights. Need DP because taking an interval affects which others we can take.
Q4: "Design an algorithm for task scheduling with dependencies."
JAVA(32 lines)CodeLoading syntax highlighter...
Q5: "What's the difference between Huffman and Shannon-Fano coding?"
| Aspect | Huffman | Shannon-Fano |
|---|---|---|
| Approach | Bottom-up (merge smallest) | Top-down (split into halves) |
| Optimality | Optimal prefix code | Near-optimal |
| Construction | Build tree from leaves | Divide symbols recursively |
| Complexity | O(n log n) | O(n log n) |
- Merging two smallest frequencies is provably safe
- Resulting tree has minimum weighted path length
Shannon-Fano can produce suboptimal codes because splitting by frequency doesn't guarantee optimal bit allocation.
π Quick Reference
Classic Greedy Problems
| Problem | Greedy Criterion | Time |
|---|---|---|
| Activity Selection | Earliest finish | O(n log n) |
| Huffman Coding | Smallest frequencies | O(n log n) |
| Fractional Knapsack | Best value/weight | O(n log n) |
| Job Scheduling (lateness) | Earliest deadline | O(n log n) |
| Minimum Spanning Tree | Smallest edge | O(E log V) |
| Dijkstra's Algorithm | Closest vertex | O((V+E) log V) |
When Greedy Fails
| Problem | Why Greedy Fails |
|---|---|
| 0/1 Knapsack | Can't take fractions |
| Coin Change (general) | Skipping a coin might be better |
| Longest Path | Local longest doesn't give global |
| Graph Coloring | Greedy can use more colors |
Proof Techniques
Exchange Argument: 1. Let OPT be optimal solution 2. If OPT differs from greedy at step k 3. Show we can swap to match greedy 4. Solution doesn't worsen β greedy is optimal Greedy Stays Ahead: 1. Define measure M (e.g., activities selected) 2. Show M(greedy, k) β₯ M(any other, k) for all k 3. By induction, greedy ends up optimal
π What's Next?
- Backtracking template
- N-Queens, Sudoku solver
- Subset/permutation generation
- Branch and bound optimization
π Review Schedule
| Day | Focus | Time |
|---|---|---|
| 0 | Full read + Activity Selection | 90 min |
| 1 | Quick Reference | 10 min |
| 3 | Implement Huffman | 25 min |
| 7 | Job scheduling exercises | 20 min |
| 14 | Debug exercise + proofs | 15 min |
| 30 | Interview questions | 15 min |