Home / Algorithms

Greedy Algorithms

Always take the best-looking option right now and never reconsider. Sometimes that is provably optimal; sometimes it walks you straight past the right answer — and this lab shows you both.

Controls

Greedy Choices

step 0

Insight

A greedy algorithm makes the locally best choice at each step and never backtracks. It is fast and simple — but only correct when the problem has the right structure.

greedy result
true optimum
verdict

Complexity

Greedy (sorted) O(n log n)
DP alternative O(n·W)
Space O(1)

Greedy Algorithms

Fast, simple, and wrong just often enough to be dangerous.

Before the details

A greedy algorithm builds a solution one step at a time, always taking whatever looks best at that moment, and never revisiting a decision. No backtracking, no lookahead.

When greedy is provably correct

Two properties are needed:

Greedy choice property. A locally optimal choice is part of some globally optimal solution.

Optimal substructure. After making that choice, the remaining problem is a smaller instance of the same problem.

Where both hold, greedy is optimal and faster than dynamic programming. Where the first fails, greedy gives an answer that may be arbitrarily bad.

ProblemGreedy optimal?
Activity selection (earliest finish time)Yes
Huffman codingYes
Minimum spanning tree (Kruskal, Prim)Yes
Dijkstra's shortest pathYes, with non-negative weights
Fractional knapsackYes
0/1 knapsackNo — needs DP
Coin change, arbitrary coinsNo — needs DP
Travelling salesmanNo — and greedy is a common heuristic

The knapsack pair is the clearest illustration. If items can be split, taking the best value-per-weight ratio first is optimal. If they cannot, that ratio can mislead — and the problem becomes NP-hard, needing dynamic programming for an exact answer.

Activity Selection: Greedy Wins

Given activities with start and finish times, pick the most that do not overlap. The greedy rule is: always take the one that finishes earliest among those still compatible.

Why is that safe? Finishing earliest leaves the maximum possible time for everything after it. Any optimal schedule can have its first activity swapped for the earliest-finishing one without reducing the count — that is the exchange argument, and it makes greedy provably optimal here.

Note that sorting by duration or start time both fail. The specific greedy criterion matters enormously.

Coin Change: Greedy Fails

With coins {1, 5, 10, 25} greedy works — always take the largest coin that fits. That is why it feels natural at a till.

Now switch to greedy FAILS, using coins {1, 3, 4} and amount 6. Greedy takes 4, then 1, then 1 — three coins. The optimum is 3 + 3 — two coins. Taking the biggest coin first stranded the algorithm in a worse position.

Nothing about the greedy code is buggy. The problem simply lacks the greedy choice property for that coin set, and only dynamic programming is guaranteed correct.

Famous Greedy Algorithms That Do Work

  • Dijkstra — always expand the nearest unvisited node. Correct only when edge weights are non-negative.
  • Kruskal and Prim — always take the cheapest safe edge. Provably build minimum spanning trees.
  • Huffman coding — always merge the two least frequent symbols. Produces optimal prefix codes.
  • Fractional knapsack — take the best value-per-weight first. Works because items can be split; the 0/1 version cannot, and needs DP.

Take the best option now, and never reconsider

A greedy algorithm makes the locally optimal choice at each step and never revisits it. No backtracking, no considering combinations — just the best-looking move, repeatedly.

That is dramatically cheaper than exploring alternatives, and it is only correct for problems with a particular structure.

Coin change with UK coins. Make 87p from 50, 20, 10, 5, 2, 1: take 50 (37 left), 20 (17), 10 (7), 5 (2), 2 (0). Five coins, and provably optimal.

Coin change with an awkward set. Make 30 from coins 25, 20, 1: greedy takes 25, then five 1s — six coins. The optimum is two 20s and... no. It is 20 + 1×10, also worse. With coins 25, 20, 10 and target 40: greedy takes 25 then 10 then five 1s if available; the optimum is two 20s. Greedy fails.

The difference is a property of the coin system, not of the algorithm. Greedy coin change is optimal for canonical systems (including UK and euro coins) and not in general — which is exactly the shape of the whole topic.

Activity selection: the canonical proof

Given intervals, select the largest number that do not overlap.

The correct greedy rule is earliest finish time, not earliest start or shortest duration:

def max_activities(intervals):
    intervals.sort(key=lambda x: x[1])        # by end time
    chosen, last_end = [], float("-inf")
    for start, end in intervals:
        if start >= last_end:
            chosen.append((start, end))
            last_end = end
    return chosen

Why earliest finish works: choosing the activity that finishes soonest leaves the maximum remaining time for everything else. Any optimal solution's first activity can be swapped for this one without reducing the count — which is an exchange argument, and it is the standard way greedy correctness is proved.

Why the alternatives fail: earliest start can pick one very long activity that blocks many; shortest duration can pick one that straddles the boundary between two others.

That distinction — the right greedy criterion versus a plausible wrong one — is where most greedy mistakes live. The algorithm is trivial; the choice of what to be greedy about is the problem.

Where greedy is provably right, and where it is confidently wrong

Greedy algorithms are the ones that take the best-looking option now and never reconsider. Sometimes that is optimal and provably so; sometimes it is merely fast. The difference is a property of the problem, and running both on the same two problems makes it concrete.

example_01.pyPython
Output

Try it yourself

  1. Run activity selection. Watch it pick the earliest finisher and reject everything that overlaps — and confirm the result matches the true optimum.
  2. Run coin change with friendly coins. Greedy and optimal agree, which is why the approach feels obviously right.
  3. Now run the failing case. Greedy returns 3 coins; the optimum is 2. Same algorithm, different coin set.
  4. Slide the amount in the failing case. Some amounts greedy gets right by luck; others it does not. There is no warning — that is what makes it dangerous.
  5. Compare the two verdicts. A greedy algorithm gives you no signal when it is wrong; you must prove correctness in advance.

In one line

Greedy algorithms are fast and elegant when the greedy choice property holds — and silently wrong when it does not. Always ask whether a locally best move can ever block a globally better one. If it can, reach for dynamic programming instead.

Greedy against dynamic programming

 GreedyDynamic programming
ChoicesOne, committedAll, compared
Revisits decisionsNoEffectively yes
Typical complexityO(n log n), often sorting-dominatedO(n×states)
CorrectnessOnly with the greedy choice propertyGeneral
MemoryO(1) beyond the inputO(states)

The practical procedure when facing a new optimisation problem: try to find a greedy rule and a counterexample. If a counterexample exists, use dynamic programming. If several attempts to break it fail, look for an exchange argument to prove it.

Do not assume greedy works because it produces plausible answers on small examples. That is how incorrect solutions ship — greedy failures are often subtle and appear only on specific inputs.

Greedy as an approximation

When exact solutions are intractable, greedy is frequently the best practical option and sometimes comes with a guarantee.

Set cover. Repeatedly take the set covering the most uncovered elements. NP-hard exactly, and greedy is within a factor of ln(n) of optimal — and no polynomial algorithm does substantially better.

Travelling salesman. Nearest-neighbour construction is fast and typically 25% worse than optimal. Christofides' algorithm guarantees within 50% for metric instances.

Job scheduling. Longest-processing-time-first is within 4/3 of optimal for minimising makespan on identical machines.

Huffman coding. Repeatedly merge the two least frequent symbols — and here greedy is exactly optimal, which is why it is used in every compression format.

So greedy occupies two roles: exactly optimal for a specific set of problems, and a strong fast approximation for many that are intractable. Knowing which situation you are in is the point.

Where greedy algorithms are used

  • Huffman coding in ZIP, JPEG, MP3 and HTTP compression.
  • Dijkstra's algorithm in every routing protocol and navigation system.
  • Minimum spanning trees for network design and clustering.
  • Interval scheduling in room booking, CPU scheduling and advertising slot allocation.
  • Cache eviction. LRU is greedy — evict the least recently used, without predicting the future.
  • Decision tree construction. Choosing the best split at each node is greedy, and it is why trees are not globally optimal.

The decision-tree case is a good closing example: finding the globally optimal tree is intractable, so every implementation is greedy, and everyone accepts a locally-optimal tree because it works well enough.

Questions people ask

How do I know greedy will work? Prove the greedy choice property with an exchange argument, or find a counterexample. There is no shortcut.

Is greedy always faster than DP? Usually, because it explores one path rather than a state space — often dominated by an initial sort.

What if greedy is wrong but close? That is an approximation algorithm, and it is frequently the right engineering answer for NP-hard problems.

Is Dijkstra greedy? Yes — it commits to the closest unvisited node, which is exactly why negative weights break it.

Can greedy be combined with DP? Yes — some DP solutions use a greedy rule to prune states, and some greedy algorithms use DP for subproblems.

Why does the greedy criterion matter so much? Because the algorithm is the criterion. Earliest-finish works for activity selection and earliest-start does not.

Recap in one screen

  • Make the locally best choice and never reconsider — cheap, and only correct with the greedy choice property.
  • Optimal for activity selection, Huffman coding, MST, Dijkstra and fractional knapsack.
  • Wrong for 0/1 knapsack, arbitrary coin systems and travelling salesman — use DP or accept an approximation.
  • The hard part is choosing what to be greedy about; earliest finish time works where earliest start does not.
  • Prove correctness with an exchange argument, or find a counterexample — do not infer it from small examples.

Run it in Python

Two greedy algorithms: one that is provably optimal and one that is confidently wrong, on inputs that differ only in the coin denominations. Both are checked against an exhaustive answer in the same run.

greedy.pyPython 3
Output

How the code works

  1. for c in sorted(coins, reverse=True):The greedy choice: largest coin that still fits. It is optimal for British, US and euro denominations, and that familiarity is exactly why people assume it is optimal in general.
  2. ([1, 3, 4], 6)The counterexample. Greedy takes 4 + 1 + 1; two 3s would do. Nothing about the algorithm changed — only the denominations — and it fails silently, with a plausible-looking answer.
  3. optimal_coins(...)A dynamic programming check run alongside, so the verdict is computed rather than asserted. This is also the practical test for whether a greedy idea is safe: compare it to brute force on small inputs.
  4. sorted(meetings, key=lambda m: m[2]) # by ENDSorting by finish time is what makes activity selection provably optimal: taking the meeting that frees the room earliest can never shut out a better schedule. There is a real exchange argument behind that, and it is what separates this from the coin case.
  5. sorted by m[1] # by STARTThe same greedy structure on a different key, and it loses immediately — one long early meeting blocks several short ones. Greedy is not a strategy on its own; the choice of key is the algorithm.

Change one thing

  • Find another denomination set where greedy fails. They are easy to construct once you look for a coin that is more than twice the one below it.
  • Sort the meetings by duration instead. Shortest-first sounds reasonable and is also wrong; build the input that breaks it.
  • Add a meeting that spans the entire day. Both strategies now have to reject something, and only one of them rejects the right thing.

Where this runs

Real CPython, compiled to WebAssembly and running on your own machine — nothing is uploaded. The first run takes a few seconds while the interpreter downloads; after that it is immediate. Need more room, or want to paste your own attempt? Use the Python compiler.

Check yourself

0 of 3

Answer without scrolling back up.

  1. Greedy coin change works for [1, 5, 10, 25] but fails for [1, 3, 4]. What does that show?

  2. Activity selection is provably optimal when the meetings are sorted by:

  3. The practical way to test a greedy idea is to:

Cheat sheet

Greedy Algorithms

Always take the best-looking option right now and never reconsider. Sometimes that is provably optimal; sometimes it walks you straight past the right answer — and this lab shows you both.

ALGORITHMS · vizlearn.in/dsa/greedy_algorithms.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.