A greedy algorithm builds a solution step-by-step by choosing the locally optimal option hoping to reach a global optimum. It is efficient and simple but requires a greedy-choice property and often optimal substructure.
// Interval scheduling: select max non-overlapping intervals
function maxNonOverlapping(intervals) {
intervals.sort((a,b) => a[1] - b[1]);
let count = 0, end = -Infinity;
for (const [s,e] of intervals) {
if (s >= end) { count++; end = e; }
}
return count;
}
A matroid M = (E, I) consists of a ground set E and a family I of independent subsets satisfying:
1) Non-empty: ∅ ∈ I
2) Hereditary: if A ∈ I and B ⊆ A then B ∈ I
3) Exchange: if A, B ∈ I and |A| > |B| then ∃ e ∈ A \ B such that B ∪ {e} ∈ I
Examples: graphic matroid (forests in a graph), partition matroid, uniform matroid, transversal matroid.
For a weighted matroid, the greedy algorithm that processes elements in decreasing weight and extends any independent set yields a maximum-weight independent set. This generalizes Kruskal's algorithm on graphic matroids.
Greedy theorem: In any matroid, greedy produces a maximum-weight base.
The exchange argument shows that any optimal solution can be transformed step-by-step to the greedy solution without worsening cost, by exchanging elements while preserving feasibility.