Greedy Algorithms and Backtracking

πŸ“– Introduction

Greedy algorithms and backtracking represent two fundamental approaches to problem-solving that I use constantly. Greedy is about making the locally optimal choice at each step, hoping it leads to a global optimum. Backtracking is about systematically exploring all possibilities.

Understanding when each approach appliesβ€”and when it doesn'tβ€”has saved me countless hours. A problem that seems to need backtracking might have a greedy solution, and vice versa.


🟒 Greedy Algorithms

A greedy algorithm makes the locally optimal choice at each step, never reconsidering past decisions.

When Greedy Works

spinner

Greedy Choice Property: A globally optimal solution can be reached by selecting the locally optimal choice.

Optimal Substructure: An optimal solution contains optimal solutions to subproblems.


πŸ“Š Classic Greedy Problems

Activity Selection

def max_activities(start: list[int], end: list[int]) -> list[int]:
    """
    Select maximum non-overlapping activities.
    Greedy: Always pick activity that ends earliest.
    Time: O(n log n)
    """
    n = len(start)
    activities = sorted(range(n), key=lambda i: end[i])
    
    result = [activities[0]]
    last_end = end[activities[0]]
    
    for i in activities[1:]:
        if start[i] >= last_end:
            result.append(i)
            last_end = end[i]
    
    return result


# Example
start = [1, 3, 0, 5, 8, 5]
end = [2, 4, 6, 7, 9, 9]
print(max_activities(start, end))  # [0, 1, 3, 4]

Jump Game

Gas Station

Task Scheduler

Partition Labels

Non-overlapping Intervals

Candy


⚠️ Greedy Pitfalls

When Greedy Fails


πŸ”™ Backtracking

Backtracking explores all possibilities by building solutions incrementally and abandoning (backtracking from) solutions that don't satisfy constraints.

Backtracking Template

spinner

πŸ“Š Backtracking Problems

Subsets

Permutations

Combinations

Combination Sum

N-Queens

Sudoku Solver


🎯 Pruning Strategies

Pruning reduces the search space by eliminating branches that can't lead to valid solutions.


πŸ“ Practice Exercises

Exercise 1: Restore IP Addresses

chevron-rightSolutionhashtag

Exercise 2: Generate Parentheses

chevron-rightSolutionhashtag

Exercise 3: Minimum Number of Arrows

chevron-rightSolutionhashtag

πŸ”‘ Key Takeaways

  1. Greedy works when local optimal leads to global optimal

  2. Verify greedy correctness or use DP if unsure

  3. Backtracking systematically explores all possibilities

  4. Template: make choice β†’ explore β†’ undo choice

  5. Pruning is essential for backtracking efficiency

  6. Sort first when order helps (both greedy and backtracking)


πŸš€ What's Next?

In the next article, we'll explore graph algorithms:

  • Shortest path algorithms (Dijkstra, Bellman-Ford)

  • Minimum spanning tree (Prim, Kruskal)

  • Topological sort

  • Union-Find data structure

Next: Article 14 - Graph Algorithms


πŸ“š References

  • CLRS Chapter 16: Greedy Algorithms

  • "Algorithm Design" - Kleinberg & Tardos

  • LeetCode Backtracking patterns

Last updated