10. Greedy Algorithms#
Theory#
Greedy builds a solution by taking the locally best choice at each step, hoping it yields a global optimum. It works only when the greedy choice property and optimal substructure can be proved (or strongly argued in an interview).
When greedy works (recognition signals)#
| Signal | Sort by / strategy | Examples |
|---|---|---|
| Interval scheduling | Earliest finish time | LC 435, 452 |
| Reachability / max reach | Track farthest index | LC 55, 45 |
| Assign cookies / two lists | Sort both, two pointers | LC 455 |
| Huffman-style merging | Always merge smallest two | LC 1167 |
When greedy fails#
If counterexamples exist (e.g. coin change with [1, 3, 4] and target 6 — greedy picks 4+1+1, optimal is 3+3), switch to DP. State why greedy fails before coding.
Interview communication#
- Propose greedy strategy in one sentence.
- Give a quick proof sketch or exchange argument (" swapping any non-greedy choice never hurts").
- State time (often O(n log n) from sorting) and O(1) extra space if in-place.
Problems at a glance#
| LC | Problem | |
|---|---|---|
| 55 | Jump Game | ↗ |
| 45 | Jump Game II | ↗ |
| 134 | Gas Station | ↗ |
| 330 | Patching Array | ↗ |
| 435 | Non-overlapping Intervals | ↗ |
| 452 | Minimum Number of Arrows to Burst Balloons | ↗ |
| 252 | Meeting Rooms | ↗ |
| 253 | Meeting Rooms II | ↗ |
| 630 | Course Schedule III | ↗ |
| 1029 | Two City Scheduling | ↗ |
| 1323 | Maximum 69 Number | ↗ |
| 2567 | Minimum Score by Changing Two Elements | ↗ |
| 3139 | Minimum Cost to Equalize Array | ↗ |
| 56 | Merge Intervals | ↗ |
| 406 | Queue Reconstruction by Height | ↗ |
| 179 | Largest Number | ↗ |
| 2449 | Minimum Number of Operations to Make Arrays Similar | ↗ |
| 621 | Task Scheduler | ↗ |
| 502 | IPO | ↗ |
| 1167 | Minimum Cost to Connect Sticks | ↗ |
| 857 | Minimum Cost to Hire K Workers | ↗ |
| 767 | Reorganize String | ↗ |
| 455 | Assign Cookies | ↗ |
| 881 | Boats to Save People | ↗ |
| 2279 | Maximum Bags With Full Capacity of Rocks | ↗ |
| 743 | Network Delay Time | ↗ |
| 1584 | Minimum Cost to Connect All Points | ↗ |
1. Greedy Choice Property#
Classic strategy: Pick the locally optimal choice at each step.
Problem 1: Activity Selection Problem (GeeksforGeeks)#
Problem Statement
Given n activities with start time start[i] and finish time end[i], select the maximum number of activities that can be performed by a single person, assuming a person can only work on one activity at a time.
Example 1:
Input: start = [1, 3, 0, 5, 8, 5], end = [2, 4, 6, 7, 9, 9]
Output: 4
Explanation: Activities (0,1), (2,3), (4) — four non-overlapping activities.
Example 2:
Input: start = [10, 12], end = [20, 25]
Output: 2
Constraints:
1 <= n <= 1050 <= start[i] < end[i] <= 109
Code and Explanation
- Greedy choice: Always pick the activity with the earliest finish time among those compatible with the last chosen activity.
- Why it works (exchange argument): Suppose an optimal solution picks activity
Xthat finishes later than the greedy pickG. SwappingXforGcannot reduce the count —Gfrees the timeline earlier, so at least as many future activities fit. - Sort by
end, scan once, keep an activity whenstart >= last_finish. - Equivalent to interval scheduling — maximize kept intervals.
Time: O(n log n) | Space: O(1) excluding sort
- Sort activities by finish time and define
dp[j]= max activities in the firstj+1sorted activities. - For each pair
(k, j)wherestart[j] >= end[k], try extending the subproblem ending atk. - Correct but O(n²) — use when you need the full DP recurrence for comparison; greedy is strictly better here.
Time: O(n²) | Space: O(n)
Problem 2: Jump Game (Leetcode:55)#
Problem Statement
You are given an integer array nums. You are initially positioned at the array's first index, and each element in the array represents your maximum jump length at that position.
Return true if you can reach the last index, or false otherwise.
Example 1:
Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
Example 2:
Input: nums = [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.
Constraints:
1 <= nums.length <= 1040 <= nums[i] <= 105
Code and Explanation
- Greedy choice: At each index, only track the farthest index reachable so far — no need to remember the exact path.
- Why it works: If index
iis reachable (i <= farthest), updatingfarthest = max(farthest, i + nums[i])captures every position reachable from any prior path. If some index is unreachable, no future step can fix it. - Return
Falsethe momenti > farthest.
Time: O(n) | Space: O(1)
- Work backward:
goalis the leftmost index that can reach the last index. - If
i + nums[i] >= goal, indexican reach the current goal, so movegoalleft toi. - Answer is whether
goalreaches index0. Same O(n) idea, different direction.
Time: O(n) | Space: O(1)
Problem 3: Jump Game II (Leetcode:45)#
Problem Statement
You are given a 0-indexed array of integers nums of length n. You are initially positioned at index 0.
Each element nums[i] represents the maximum length of a forward jump from index i. In other words, if you are at index i, you can jump to any index (i + j) where:
0 <= j <= nums[i]andi + j < n
Return the minimum number of jumps to reach index n - 1. The test cases are generated such that you can reach index n - 1.
Example 1:
Input: nums = [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2. Jump 1 step from index 0 to 1, then 3 steps to the last index.
Example 2:
Input: nums = [2,3,0,1,4]
Output: 2
Constraints:
1 <= nums.length <= 1040 <= nums[i] <= 1000- It's guaranteed that you can reach
nums[n - 1].
Code and Explanation
- Greedy choice: When the current jump range ends (
i == curr_end), take one more jump and extend the range to the farthest index seen so far. - Why it works: Within one "level" of jumps you always record the maximum reach (
farthest). The first time you are forced to jump again, that maximum is the best single extension — any solution needing the same number of jumps cannot reach farther on this level. - Analogous to BFS layers on an implicit graph.
Time: O(n) | Space: O(1)
- BFS from index
0finds the shortest path in the implicit jump graph. - Correct but explores many redundant states; the level-greedy approach above is the intended O(n) solution.
Time: O(n²) worst case | Space: O(n)
Problem 4: Gas Station (Leetcode:134)#
Problem Statement
There are n gas stations along a circular route, where the amount of gas at the ith station is gas[i].
You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from the ith station to its next (i + 1)th station. You begin the journey with an empty tank at one of the gas stations.
Given two integer arrays gas and cost, return the starting gas station's index if you can travel around the circuit once in the clockwise direction, otherwise return -1. If there exists a solution, it is guaranteed to be unique.
Example 1:
Input: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
Output: 3
Explanation:
Start at station 3 (index 3) and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 4. Your tank = 4 - 1 + 5 = 8
Travel to station 0. Your tank = 8 - 2 + 1 = 7
Travel to station 1. Your tank = 7 - 3 + 2 = 6
Travel to station 2. Your tank = 6 - 4 + 3 = 5
Travel to station 3. The cost is 5. Your gas is just enough to travel back to station 3.
Therefore, return 3 as the starting index.
Example 2:
Input: gas = [2,3,4], cost = [3,4,3]
Output: -1
Explanation:
You can't start at station 0 or 1, as there is not enough gas to travel to the next station.
Let's start at station 2 and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 0. Your tank = 4 - 3 + 2 = 3
Travel to station 1. Your tank = 3 - 3 + 3 = 3
You cannot travel back to station 2, as it requires 4 unit of gas but you only have 3.
Therefore, you can't travel around the circuit once no matter where you start.
Constraints:
n == gas.length == cost.length1 <= n <= 1050 <= gas[i], cost[i] <= 104- The input is generated such that the answer is unique.
Code and Explanation
- Greedy choice: If the tank goes negative after passing station
i, no station fromstartthroughican be a valid starting point — resetstart = i + 1. - Why it works: Any start between the old
startandiwould inherit a non-positive tank before reachingi+1. Combined withsum(gas) >= sum(cost), the first feasiblestartcompletes the circuit. - Pre-check total gas vs total cost for impossibility.
Time: O(n) | Space: O(1)
- Try every station as the start and simulate the full circuit.
- Correct but O(n²) — the tank-reset greedy eliminates all failed prefixes in one pass.
Time: O(n²) | Space: O(1)
Problem 5: Patching Array (Leetcode:330)#
Problem Statement
Given a sorted integer array nums and an integer n, add/patch elements to the array such that any number in the range [1, n] inclusive can be formed by the sum of some elements in the array.
Return the minimum number of patches required.
Example 1:
Input: nums = [1,3], n = 6
Output: 1
Explanation:
Combinations of nums are [1], [3], [1,3], which form possible sums of: 1, 3, 4.
Now if we add/patch 2 to nums, the combinations are: [1], [2], [3], [1,3], [2,3], [1,2,3].
Possible sums are 1, 2, 3, 4, 5, 6, which now covers the range [1, 6].
So we only need 1 patch.
Example 2:
Input: nums = [1,5,10], n = 20
Output: 2
Explanation: The two patches can be [2, 4].
Example 3:
Input: nums = [1,2,2], n = 5
Output: 0
Constraints:
1 <= nums.length <= 10001 <= nums[i] <= 104numsis sorted in ascending order.1 <= n <= 231 - 1
Code and Explanation
- Greedy choice: Maintain
coverage= largest contiguous sum range[1, coverage]formable. If the next existing number<= coverage + 1, extend; otherwise patchcoverage + 1(the smallest missing sum). - Why it works: Patching
coverage + 1doubles the reachable range to[1, 2·coverage + 1]. Any smaller patch leaves a gap that wastes a patch later. Using an existing number when it fits is never worse than patching. - Stop when
coverage >= n.
Time: O(m) where m = len(nums) | Space: O(1)
- State:
(idx, coverage)→ minimum patches to cover[1, n]. - Transitions: use
nums[idx]if it fits, or patchcoverage + 1. - Illustrates why greedy works; impractical for large
ndue to state space.
Time: Exponential / pseudo-polynomial | Space: O(states)
2. Interval Scheduling#
Pick maximum number of non-overlapping intervals by sorting based on end time.
Problem 1: Non-overlapping Intervals (Leetcode:435)#
Problem Statement
Given an array of intervals intervals where intervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.
Note that intervals which only touch at a point are non-overlapping. For example, [1, 2] and [2, 3] are non-overlapping.
Example 1:
Input: intervals = [[1,2],[2,3],[3,4],[1,3]]
Output: 1
Explanation: [1,3] can be removed and the rest of the intervals are non-overlapping.
Example 2:
Input: intervals = [[1,2],[1,2],[1,2]]
Output: 2
Explanation: You need to remove two [1,2] to make the rest of the intervals non-overlapping.
Example 3:
Input: intervals = [[1,2],[2,3]]
Output: 0
Explanation: You don't need to remove any of the intervals since they're already non-overlapping.
Constraints:
1 <= intervals.length <= 105intervals[i].length == 2-5 * 104 <= starti < endi <= 5 * 104
Code and Explanation
- Greedy choice: Sort by end time and keep the interval with the earliest finish among compatible ones.
- Why it works: Same exchange argument as Activity Selection — finishing earlier preserves maximum room for future intervals, maximizing the kept count; removals =
n - kept. - Touching intervals (
end == start) count as non-overlapping.
Time: O(n log n) | Space: O(1)
dp[i]= max non-overlapping intervals ending at or before indexi.- O(n²) DP — correct but greedy is the intended solution.
Time: O(n²) | Space: O(n)
Problem 2: Minimum Number of Arrows to Burst Balloons (Leetcode:452)#
Problem Statement
There are some spherical balloons taped onto a flat wall that represents the XY-plane. The balloons are represented as a 2D integer array points where points[i] = [xstart, xend] denotes a balloon whose horizontal diameter stretches between xstart and xend. You do not know the exact y-coordinates of the balloons.
Arrows can be shot up directly vertically (in the positive y-direction) from different points along the x-axis. A balloon with xstart and xend is burst by an arrow shot at x if xstart <= x <= xend. There is no limit to the number of arrows that can be shot. A shot arrow keeps traveling up infinitely, bursting any balloons in its path.
Given the array points, return the minimum number of arrows that must be shot to burst all balloons.
Example 1:
Input: points = [[10,16],[2,8],[1,6],[7,12]]
Output: 2
Explanation: The balloons can be burst by 2 arrows:
- Shoot an arrow at x = 6, bursting the balloons [2,8] and [1,6].
- Shoot an arrow at x = 11, bursting the balloons [10,16] and [7,12].
Example 2:
Input: points = [[1,2],[3,4],[5,6],[7,8]]
Output: 4
Explanation: One arrow needs to be shot for each balloon for a total of 4 arrows.
Example 3:
Input: points = [[1,2],[2,3],[3,4],[4,5]]
Output: 2
Explanation: The balloons can be burst by 2 arrows:
- Shoot an arrow at x = 2, bursting the balloons [1,2] and [2,3].
- Shoot an arrow at x = 4, bursting the balloons [3,4] and [4,5].
Constraints:
1 <= points.length <= 105points[i].length == 2-231 <= xstart < xend <= 231 - 1
Code and Explanation
- Greedy choice: Sort balloons by right endpoint; place each new arrow at the right end of the first uncovered balloon.
- Why it works: An arrow at
endbursts every balloon whose right end is>= endand whose left end is<= end. Shooting further right only shrinks coverage on the left; shooting left wastes overlap with future balloons. - Dual to interval scheduling — minimize arrows = maximize overlap groups.
Time: O(n log n) | Space: O(1)
- Sort by start, track the current arrow's position (
curr_end). - When a balloon starts after
curr_end, fire a new arrow at itsend; otherwise shrinkcurr_endto the overlap. - Same greedy logic, different sort order.
Time: O(n log n) | Space: O(1)
3. Interval Partitioning / Sweep Line (Heap-based Resource Allocation)#
Allocate resources to overlapping intervals using min-heaps.
Problem 1: Meeting Rooms (Leetcode:252)#
Problem Statement
Given an array of meeting time intervals intervals where intervals[i] = [starti, endi], determine if a person could attend all meetings.
Example 1:
Input: intervals = [[0,30],[5,10],[15,20]]
Output: false
Example 2:
Input: intervals = [[7,10],[2,4]]
Output: true
Constraints:
0 <= intervals.length <= 104intervals[i].length == 20 <= starti < endi <= 106
Code and Explanation
- Greedy choice: Sort by start time; only check adjacent meetings after sorting.
- Why it works: If any two meetings overlap, sorting places them adjacent (or with an overlapping chain). One linear scan suffices.
- Overlap iff
start[i] < end[i-1].
Time: O(n log n) | Space: O(1)
- Convert intervals to +1 / −1 events; sort by time.
- If active meetings ever exceed 1, overlap exists.
- Generalizes to "max concurrent meetings" problems.
Time: O(n log n) | Space: O(n)
Problem 2: Meeting Rooms II (Leetcode:253)#
Problem Statement
Given an array of meeting time intervals, return the minimum number of conference rooms required.
Example 1:
Input: intervals = [[0,30],[5,10],[15,20]]
Output: 2
Example 2:
Input: intervals = [[7,10],[2,4]]
Output: 1
Constraints:
1 <= intervals.length <= 1040 <= starti < endi <= 106
Code and Explanation
- Greedy choice: Process meetings by start time; reuse the room that frees earliest (min-heap of end times) if
heap[0] <= start. - Why it works: Assigning to the soonest-free room minimizes room count — delaying a free room never helps future assignments (exchange argument on resource release time).
- Heap size at the end = peak concurrent meetings = rooms needed.
Time: O(n log n) | Space: O(n)
- Two pointers over sorted starts and ends.
- Start before next end → need another room; else a meeting ended → free a room.
- Track the maximum concurrent count.
Time: O(n log n) | Space: O(n)
Problem 3: Minimum Platforms (GeeksforGeeks)#
Problem Statement
Given arrival and departure times of trains at a railway station, find the minimum number of platforms required so that no train waits.
Example 1:
Input: arr = [900, 940, 950, 1100, 1500, 1800], dep = [910, 1200, 1120, 1130, 1900, 2000]
Output: 3
Example 2:
Input: arr = [900, 940], dep = [910, 1200]
Output: 2
Constraints:
1 <= n <= 1051 <= arr[i], dep[i] <= 5000
Code and Explanation
- Greedy choice: Sort arrivals and departures; process the earlier event next — if next arrival ≤ next departure, a train arrives before one leaves → need another platform.
- Why it works: Identical to Meeting Rooms II — peak concurrent occupancy is the answer. Only the chronological order of events matters.
- Start with one platform (first train).
Time: O(n log n) | Space: O(1)
- +1 for arrival, −1 for departure; sort all events.
- Running sum = trains currently at station; maximum = platforms needed.
- Handles equal timestamps naturally (process arrivals before departures if needed via tuple tie-break).
Time: O(n log n) | Space: O(n)
4. Earliest Deadline First / Shortest Job First#
Sort tasks by deadline or duration.
Problem 1: Job Sequencing Problem (GeeksforGeeks)#
Problem Statement
Given n jobs, each with a deadline and profit, schedule jobs on a single machine (one job per unit time slot) to maximize total profit. Each job takes one unit of time; only one job runs at a time.
Example 1:
Input: jobs = [(id, deadline, profit)] = [(1,2,100), (2,1,19), (3,2,27), (4,1,25), (5,3,15)]
Output: 142 (jobs 1, 3, 5)
Example 2:
Input: jobs = [(1,1,20), (2,1,10)]
Output: 20
Constraints:
1 <= n <= 1051 <= deadline <= n1 <= profit <= 104
Code and Explanation
- Greedy choice: Process jobs in descending profit; assign each to its latest free slot at or before its deadline.
- Why it works: High-profit jobs are prioritized. Placing a job as late as possible preserves earlier slots for other jobs with tighter deadlines — an exchange argument on slot assignment.
- Disjoint-set optimization can replace the inner loop for O(n log n).
Time: O(n · d) where d = max deadline | Space: O(d)
- Union-find tracks the next available slot ≤ a given deadline.
find(d)returns the latest free slot; link it toslot - 1.- Same greedy order, faster slot lookup.
Time: O(n log n) amortized | Space: O(d)
Problem 2: Course Schedule III (Leetcode:630)#
Problem Statement
There are n different online courses numbered from 1 to n. You are given an array courses where courses[i] = [durationi, lastDayi] indicate that the ith course should be taken continuously for durationi days and must be finished before or on lastDayi.
You will start on the 1st day and you cannot take two or more courses simultaneously.
Return the maximum number of courses that you can take.
Example 1:
Input: courses = [[100,200],[200,1300],[1000,1250],[2000,3200]]
Output: 3
Explanation:
There are totally 4 courses, but you can take 3 courses at most:
First, take the 1st course, it costs 100 days so you will finish it on the 100th day, and ready to take the next course on the 101st day.
Second, take the 3rd course, it costs 1000 days so you will finish it on the 1100th day, and ready to take the next course on the 1101st day.
Third, take the 2nd course, it costs 200 days so you will finish it on the 1300th day.
The 4th course cannot be taken now, since you will finish it on the 3300th day, which exceeds the closed date.
Example 2:
Input: courses = [[1,2]]
Output: 1
Example 3:
Input: courses = [[3,2],[4,3]]
Output: 0
Constraints:
1 <= courses.length <= 1041 <= durationi, lastDayi <= 104
Code and Explanation
- Greedy choice: Sort by deadline (Earliest Deadline First). When total time exceeds
last_day, drop the longest scheduled course. - Why it works: For a fixed set of courses, removing the longest duration frees the most time while losing only one slot. Processing urgent deadlines first ensures we only sacrifice courses when necessary.
- Max-heap (negated durations) tracks scheduled courses.
Time: O(n log n) | Space: O(n)
dp[i]= max courses among firstiafter sorting by deadline.- Try adding course
ito every feasible prior state. - O(n²) — greedy + heap is the standard efficient solution.
Time: O(n²) | Space: O(n)
5. Minimize or Maximize a Value#
Greedy numeric optimization using a custom value function.
Problem 1: Fractional Knapsack (GeeksforGeeks)#
Problem Statement
Given item weights and values and a knapsack capacity W, maximize total value. Fractions of items are allowed (unlike 0/1 knapsack).
Example 1:
Input: values = [60, 100, 120], weights = [10, 20, 30], W = 50
Output: 240.0 (take all of items 1 & 2, 20/30 of item 3)
Example 2:
Input: values = [10, 20, 30], weights = [5, 10, 15], W = 100
Output: 60.0 (take everything)
Constraints:
1 <= n <= 1051 <= weights[i], values[i] <= 104
Code and Explanation
- Greedy choice: Take items in descending value/weight ratio; fully take each item or fill remaining capacity fractionally.
- Why it works: Any solution can be converted to one that prioritizes higher ratio items first without decreasing value (exchange: swap a smaller-ratio portion for larger-ratio).
- Note: 0/1 knapsack fails this greedy property — see DP doc.
Time: O(n log n) | Space: O(1)
- Included to contrast: 0/1 knapsack cannot use ratio greedy (counterexample: weights [10,20], values [60,100], W=50).
- Fractional version's greedy optimality is what makes this problem a greedy classic.
Time: O(n · W) | Space: O(W)
Problem 2: Two City Scheduling (Leetcode:1029)#
Problem Statement
A company is planning to interview 2n people. Given the array costs where costs[i] = [aCosti, bCosti], the cost of flying the ith person to city a is aCosti, and the cost of flying the ith person to city b is bCosti.
Return the minimum cost to fly every person to a city such that exactly n people arrive in each city.
Example 1:
Input: costs = [[10,20],[30,200],[400,50],[30,20]]
Output: 110
Explanation:
The first person goes to city A for a cost of 10.
The second person goes to city A for a cost of 30.
The third person goes to city B for a cost of 50.
The fourth person goes to city B for a cost of 20.The total minimum cost is 10 + 30 + 50 + 20 = 110 to have half the people interviewing in each city.
Example 2:
Input: costs = [[259,770],[448,54],[926,667],[184,139],[840,118],[577,469]]
Output: 1859
Example 3:
Input: costs = [[515,563],[451,713],[537,709],[343,819],[855,779],[457,60],[650,359],[631,42]]
Output: 3086
Constraints:
2 * n == costs.length2 <= costs.length <= 100costs.lengthis even.1 <= aCosti, bCosti <= 1000
Code and Explanation
- Greedy choice: Sort by
aCost - bCost. Send the first n people (largest savings for city A) to A; rest to B. - Why it works: Each person contributes
min(a,b) + |a-b|/2conceptually; assigning high(a-b)to A and low/negative to B minimizes total|a-b|sum subject tonper city. - Exactly
nmust go to each city — sorting + split achieves balance.
Time: O(n log n) | Space: O(1)
- Try all
C(2n, n)ways to assignnpeople to city A. - Correct but exponential — greedy captures the cost-difference structure.
Time: O(C(2n,n) · n) | Space: O(n)
Problem 3: Maximum 69 Number (Leetcode:1323)#
Problem Statement
You are given a positive integer num consisting only of digits 6 and 9.
Return the maximum number you can get by changing at most one digit (6 becomes 9, and 9 becomes 6).
Example 1:
Input: num = 9669
Output: 9969
Explanation:
Changing the first digit results in 6669.
Changing the second digit results in 9969.
Changing the third digit results in 9699.
Changing the fourth digit results in 9666.
The maximum number is 9969.
Example 2:
Input: num = 9996
Output: 9999
Explanation: Changing the last digit 6 to 9 results in the maximum number.
Example 3:
Input: num = 9999
Output: 9999
Explanation: It is better not to apply any change.
Constraints:
1 <= num <= 104numconsists of only6and9digits.
Code and Explanation
- Greedy choice: Flip the leftmost
6to9(at most one flip). - Why it works: A higher place value contributes more;
9in the leftmost eligible position dominates any flip to the right. If no6exists, the number is already maximal. - Single left-to-right scan.
Time: O(log num) digits | Space: O(log num)
- Flipping
6 → 9at positioni(from left) adds3 × 10^(place). - Same greedy rule — first
6from the most significant side.
Time: O(log num) | Space: O(log num)
Problem 4: Minimum Score by Changing Two Elements (Leetcode:2567)#
Problem Statement
You are given an integer array nums.
- The low score of
numsis the minimum absolute difference between any two integers. - The high score of
numsis the maximum absolute difference between any two integers. - The score of
numsis the sum of the high and low scores.
Return the minimum score after changing two elements of nums.
Example 1:
Input: nums = [1,4,7,8,5]
Output: 3
Explanation:
Changenums[0]andnums[1]to be 6 so thatnumsbecomes [6,6,7,8,5].
The low score is the minimum absolute difference: |6 - 6| = 0.
The high score is the maximum absolute difference: |8 - 5| = 3.
The sum of high and low score is 3.
Example 2:
Input: nums = [1,4,3]
Output: 0
Explanation:
Changenums[1]andnums[2]to 1 so thatnumsbecomes [1,1,1].
The sum of maximum absolute difference and minimum absolute difference is 0.
Constraints:
3 <= nums.length <= 1051 <= nums[i] <= 109
Code and Explanation
- Greedy choice: After sorting, only three configurations matter: make all equal (score 0), collapse the low gap among the three smallest, or collapse the high gap among the three largest.
- Why it works: Score =
(max - min) + (second_min_gap). Changing two elements lets you either zero both terms (all equal), eliminate the min gap (raise two smallest tonums[2]), or eliminate the max gap (lower two largest tonums[-3]). No other pair beats one of these. n <= 3always achieves score 0.
Time: O(n log n) | Space: O(1)
- Try changing each pair to candidate values — validates the three-case greedy.
- Impractical for large
n; the sorted case analysis is O(n log n).
Time: O(n³) | Space: O(n)
Problem 5: Minimum Cost to Equalize Array (Leetcode:3139)#
Problem Statement
You are given an integer array nums and two integers cost1 and cost2. You are allowed to perform either of the following operations any number of times:
- Choose an index
ifromnumsand increasenums[i]by1for a cost ofcost1. - Choose two different indices
i,j, fromnumsand increasenums[i]andnums[j]by1for a cost ofcost2.
Return the minimum cost required to make all elements in the array equal.
Since the answer may be very large, return it modulo 109 + 7.
Example 1:
Input: nums = [4,1], cost1 = 5, cost2 = 2
Output: 15
Explanation:
The following operations can be performed to make the values equal:
Increasenums[1]by 1 for a cost of 5.numsbecomes[4,2].
Increasenums[1]by 1 for a cost of 5.numsbecomes[4,3].
* Increasenums[1]by 1 for a cost of 5.numsbecomes[4,4].
The total cost is 15.
Example 2:
Input: nums = [2,3,3,3,5], cost1 = 2, cost2 = 1
Output: 6
Explanation:
The following operations can be performed to make the values equal:
Increasenums[0]andnums[1]by 1 for a cost of 1.numsbecomes[3,4,3,3,5].
Increasenums[0]andnums[2]by 1 for a cost of 1.numsbecomes[4,4,4,3,5].
Increasenums[0]andnums[3]by 1 for a cost of 1.numsbecomes[5,4,4,4,5].
Increasenums[1]andnums[2]by 1 for a cost of 1.numsbecomes[5,5,5,4,5].
* Increasenums[3]by 1 for a cost of 2.numsbecomes[5,5,5,5,5].
The total cost is 6.
Example 3:
Input: nums = [3,5,3], cost1 = 1, cost2 = 3
Output: 4
Explanation:
The following operations can be performed to make the values equal:
Increasenums[0]by 1 for a cost of 1.numsbecomes[4,5,3].
Increasenums[0]by 1 for a cost of 1.numsbecomes[5,5,3].
Increasenums[2]by 1 for a cost of 1.numsbecomes[5,5,4].
Increasenums[2]by 1 for a cost of 1.numsbecomes[5,5,5].
The total cost is 4.
Constraints:
1 <= nums.length <= 1051 <= nums[i] <= 1061 <= cost1 <= 1061 <= cost2 <= 106
Code and Explanation
- Greedy choice: Raising all elements to target
Tneedsinc = Σ(T - nums[i])unit increments. Use pair operations (costcost2) greedily whencost2 < 2·cost1; otherwise use only singles. - Why it works: Pair ops are interchangeable across elements — optimal count is
⌊inc/2⌋pairs +inc mod 2singles. OnlyT = maxorT = max+1can be optimal (parity of deficits matters). - Compare pure-single vs pair+singles cost per target.
Time: O(n) | Space: O(1)
- Same logic, explicit loop over two candidate targets.
- No DP needed — the cost function is monotonic and the pair/single decision is local.
Time: O(n) | Space: O(1)
6. Greedy with Sorting#
Sort based on custom logic and process sequentially.
Problem 1: Merge Intervals (Leetcode:56)#
Problem Statement
Given an array of intervals where intervals[i] = [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.
Example 1:
Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlap, merge them into [1,6].
Example 2:
Input: intervals = [[1,4],[4,5]]
Output: [[1,5]]
Explanation: Intervals [1,4] and [4,5] are considered overlapping.
Constraints:
1 <= intervals.length <= 104intervals[i].length == 20 <= starti <= endi <= 104
Code and Explanation
- Greedy choice: Sort by start; merge current interval into the last merged if
start <= last.end, else start a new group. - Why it works: After sorting, overlaps form contiguous chains. Extending the last interval's end to
max(end, last.end)captures the full chain without missing any overlap. - Touching intervals (
start == last.end) merge per problem definition.
Time: O(n log n) | Space: O(n) output
- Event-based merge: +1 at start, −1 after end.
- When depth returns to 0, one merged interval closes.
- Alternative view; sort-by-start greedy is simpler.
Time: O(n log n) | Space: O(n)
Problem 2: Queue Reconstruction by Height (Leetcode:406)#
Problem Statement
You are given an array of people, people, which are the attributes of some people in a queue (not necessarily in order). Each people[i] = [hi, ki] represents the ith person of height hi with exactly ki other people in front who have a height greater than or equal to hi.
Reconstruct and return the queue that is represented by the input array people. The returned queue should be formatted as an array queue, where queue[j] = [hj, kj] is the attributes of the jth person in the queue (queue[0] is the person at the front of the queue).
Example 1:
Input: people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
Output: [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
Explanation:
Person 0 has height 5 with no other people taller or the same height in front.
Person 1 has height 7 with no other people taller or the same height in front.
Person 2 has height 5 with two persons taller or the same height in front, which is person 0 and 1.
Person 3 has height 6 with one person taller or the same height in front, which is person 1.
Person 4 has height 4 with four people taller or the same height in front, which are people 0, 1, 2, and 3.
Person 5 has height 7 with one person taller or the same height in front, which is person 1.
Hence [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] is the reconstructed queue.
Example 2:
Input: people = [[6,0],[5,0],[4,0],[3,2],[2,2],[1,4]]
Output: [[4,0],[5,0],[2,2],[3,2],[1,4],[6,0]]
Constraints:
1 <= people.length <= 20000 <= hi <= 1060 <= ki < people.length- It is guaranteed that the queue can be reconstructed.
Code and Explanation
- Greedy choice: Sort by height descending, then
kascending. Insert each person at indexkin the result list. - Why it works: When placing a person, all already-placed people are taller or equal. Their positions are fixed, so index
kis exactly "count of people ≥ h in front." Shorter people inserted later don't affect taller people'skcounts. - Processing tallest-first makes each insertion well-defined.
Time: O(n²) due to list insert | Space: O(n)
- Sort by
kascending, height descending; place each person at thek-th empty slot. - Same greedy invariant from the short-person perspective.
- BIT can optimize to O(n log n); list insert is acceptable for n ≤ 2000.
Time: O(n²) | Space: O(n)
Problem 3: Largest Number (Leetcode:179)#
Problem Statement
Given a list of non-negative integers nums, arrange them such that they form the largest number and return it.
Since the result may be very large, so you need to return a string instead of an integer.
Example 1:
Input: nums = [10,2]
Output: "210"
Example 2:
Input: nums = [3,30,34,5,9]
Output: "9534330"
Constraints:
1 <= nums.length <= 1000 <= nums[i] <= 109
Code and Explanation
- Greedy choice: Sort numbers so that for any adjacent pair
(a, b),a+b >= b+alexicographically as integers. - Why it works: If
ab > ba, placingabeforebis locally optimal; transitivity of this relation yields a global optimal concatenation (exchange argument on adjacent swaps). - Handle all-zeros edge case →
"0".
Time: O(n log n · k) where k = digit length | Space: O(n)
- Compact comparator form of the same greedy sort.
- No DP or backtracking needed — the custom sort fully determines order.
Time: O(n log n · k) | Space: O(n)
Problem 4: Minimum Number of Operations to Make Arrays Similar (Leetcode:2449)#
Problem Statement
You are given two positive integer arrays nums and target, of the same length.
In one operation, you can choose any two distinct indices i and j where 0 <= i, j < nums.length and:
- set
nums[i] = nums[i] + 2and - set
nums[j] = nums[j] - 2.
Two arrays are considered to be similar if the frequency of each element is the same.
Return the minimum number of operations required to make nums similar to target. The test cases are generated such that nums can always be similar to target.
Example 1:
Input: nums = [8,12,6], target = [2,14,10]
Output: 2
Explanation: It is possible to make nums similar to target in two operations:
- Choose i = 0 and j = 2, nums = [10,12,4].
- Choose i = 1 and j = 2, nums = [10,14,2].
It can be shown that 2 is the minimum number of operations needed.
Example 2:
Input: nums = [1,2,5], target = [4,1,3]
Output: 1
Explanation: We can make nums similar to target in one operation:
- Choose i = 1 and j = 2, nums = [1,4,3].
Example 3:
Input: nums = [1,1,1,1,1], target = [1,1,1,1,1]
Output: 0
Explanation: The array nums is already similiar to target.
Constraints:
n == nums.length == target.length1 <= n <= 1051 <= nums[i], target[i] <= 106- It is possible to make
numssimilar totarget.
Code and Explanation
- Greedy choice: Sort both arrays; pair
nums[i]withtarget[i]. Each operation moves ±2 on two elements, so total unit imbalance must be fixed in pairs. - Why it works: Similar arrays have the same multiset — sorted pairing minimizes per-index distance. Each
+2/-2op fixes 4 units of total absolute gap, so ops =Σ|diff| / 4. - Problem guarantees feasibility (even total adjustment).
Time: O(n log n) | Space: O(1)
- Traces surplus/deficit of +2 units after sorting.
- Confirms each operation resolves two ±2 imbalances simultaneously.
- Same answer as Approach 1 — validates the /4 formula.
Time: O(n log n) | Space: O(1)
7. Greedy with Heap / Priority Queue#
Use heap to dynamically select optimal elements.
Problem 1: Huffman Coding (GeeksforGeeks)#
Problem Statement
Given character frequencies, build a minimum-length prefix-free binary code (Huffman coding). Return the minimum total encoded bits for a message, or the code tree.
Example 1:
Input: chars = ['a','b','c','d','e'], freq = [5,9,12,13,16]
Output: Minimum weighted path length = 224 (for total char count sum)
Example 2:
Input: freq = [1, 1, 2]
Output: Merge 1+1=2, then 2+2=4 → optimal prefix code
Constraints:
1 <= n <= 1051 <= freq[i] <= 109
Code and Explanation
- Greedy choice: Repeatedly merge the two smallest frequencies (min-heap).
- Why it works: Lowest-frequency characters should have the longest codes — merging smallest subtrees first minimizes weighted depth (classic Huffman optimality proof by induction).
- Same structure as LC 1167 (Connect Sticks).
Time: O(n log n) | Space: O(n)
- Optimal prefix codes have a greedy structure — no efficient DP alternative.
- DP approaches to optimal binary trees (e.g. matrix chain) differ; Huffman is specifically greedy.
Time: O(n log n) | Space: O(n)
Problem 2: Task Scheduler (Leetcode:621)#
Problem Statement
You are given an array of CPU tasks, each labeled with a letter from A to Z, and a number n. Each CPU interval can be idle or allow the completion of one task. Tasks can be completed in any order, but there's a constraint: there has to be a gap of at least n intervals between two tasks with the same label.
Return the minimum number of CPU intervals required to complete all tasks.
Example 1:
Input: tasks = ["A","A","A","B","B","B"], n = 2
Output: 8
Explanation: A possible sequence is: A -> B -> idle -> A -> B -> idle -> A -> B.
After completing task A, you must wait two intervals before doing A again. The same applies to task B. In the 3rd interval, neither A nor B can be done, so you idle. By the 4th interval, you can do A again as 2 intervals have passed.
Example 2:
Input: tasks = ["A","C","A","B","D","B"], n = 1
Output: 6
Explanation: A possible sequence is: A -> B -> C -> D -> A -> B.
With a cooling interval of 1, you can repeat a task after just one other task.
Example 3:
Input: tasks = ["A","A","A", "B","B","B"], n = 3
Output: 10
Explanation: A possible sequence is: A -> B -> idle -> idle -> A -> B -> idle -> idle -> A -> B.
There are only two types of tasks, A and B, which need to be separated by 3 intervals. This leads to idling twice between repetitions of these tasks.
Constraints:
1 <= tasks.length <= 104tasks[i]is an uppercase English letter.0 <= n <= 100
Code and Explanation
- Greedy choice: Schedule the most frequent task first, leaving
nidle/other slots between repeats. Frame:(maxCount-1)groups of(n+1)slots + final group of all max-frequency tasks. - Why it works: The bottleneck is the most common task — it forces at least
(maxCount-1)·ngaps. If enough other tasks fill gaps, answer =len(tasks); else idle slots pad tomin_length. max(len(tasks), min_length)handles surplus tasks.
Time: O(m) where m = len(tasks) | Space: O(1) — 26 letters
- Greedily pick the most frequent available task; push back after
ncooldown. - Simulates the optimal schedule step by step.
- O(m log 26) — formula approach is preferred for interviews.
Time: O(m log k) | Space: O(k)
Problem 3: IPO (Leetcode:502)#
Problem Statement
Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares to Venture Capital, LeetCode would like to work on some projects to increase its capital before the IPO. Since it has limited resources, it can only finish at most k distinct projects before the IPO. Help LeetCode design the best way to maximize its total capital after finishing at most k distinct projects.
You are given n projects where the ith project has a pure profit profits[i] and a minimum capital of capital[i] is needed to start it.
Initially, you have w capital. When you finish a project, you will obtain its pure profit and the profit will be added to your total capital.
Pick a list of at most k distinct projects from given projects to maximize your final capital, and return the final maximized capital.
The answer is guaranteed to fit in a 32-bit signed integer.
Example 1:
Input: k = 2, w = 0, profits = [1,2,3], capital = [0,1,1]
Output: 4
Explanation: Since your initial capital is 0, you can only start the project indexed 0.
After finishing it you will obtain profit 1 and your capital becomes 1.
With capital 1, you can either start the project indexed 1 or the project indexed 2.
Since you can choose at most 2 projects, you need to finish the project indexed 2 to get the maximum capital.
Therefore, output the final maximized capital, which is 0 + 1 + 3 = 4.
Example 2:
Input: k = 3, w = 0, profits = [1,2,3], capital = [0,1,2]
Output: 6
Constraints:
1 <= k <= 1050 <= w <= 109n == profits.lengthn == capital.length1 <= n <= 1050 <= profits[i] <= 1040 <= capital[i] <= 109
Code and Explanation
- Greedy choice: Among affordable projects, always pick the highest profit (max-heap). Sort projects by capital requirement.
- Why it works: With fixed current capital, taking a lower-profit project never enables a better total — extra capital only unlocks more projects, and max profit maximizes the next unlock frontier.
- Repeat
ktimes; push newly affordable projects each round.
Time: O(n log n) | Space: O(n)
- Try all subsets of size ≤ k — exponential.
- Greedy per-round max-profit is correct due to matroid-like structure of "pick affordable, gain profit."
Time: Exponential | Space: O(n)
Problem 4: Minimum Cost to Connect Sticks (Leetcode:1167)#
Problem Statement
You have n sticks of various lengths. In each step, pick any two sticks and merge them with cost = sum of their lengths. Return the minimum total cost to connect all sticks into one.
Example 1:
Input: sticks = [2,4,3]
Output: 14
Explanation: Merge 2+3=5 (cost 5), then 4+5=9 (cost 9). Total = 14.
Example 2:
Input: sticks = [1,8,3,5]
Output: 30
Constraints:
1 <= sticks.length <= 1041 <= sticks[i] <= 104
Code and Explanation
- Greedy choice: Always merge the two shortest sticks first.
- Why it works: Shorter sticks are cheapest to include in intermediate merges — delaying them increases their contribution to future merge costs (identical to Huffman tree optimality).
- Min-heap extracts the two smallest each step.
Time: O(n log n) | Space: O(n)
- Try all merge pairs — exponential state space.
- Confirms greedy optimality; impractical beyond tiny inputs.
Time: Exponential | Space: O(states)
Problem 5: Minimum Cost to Hire K Workers (Leetcode:857)#
Problem Statement
There are n workers. You are given two integer arrays quality and wage where quality[i] is the quality of the ith worker and wage[i] is the minimum wage expectation for the ith worker.
We want to hire exactly k workers to form a paid group. To hire a group of k workers, we must pay them according to the following rules:
- Every worker in the paid group must be paid at least their minimum wage expectation.
- In the group, each worker's pay must be directly proportional to their quality. This means if a worker’s quality is double that of another worker in the group, then they must be paid twice as much as the other worker.
Given the integer k, return the least amount of money needed to form a paid group satisfying the above conditions. Answers within 10-5 of the actual answer will be accepted.
Example 1:
Input: quality = [10,20,5], wage = [70,50,30], k = 2
Output: 105.00000
Explanation: We pay 70 to 0th worker and 35 to 2nd worker.
Example 2:
Input: quality = [3,1,10,10,1], wage = [4,8,2,2,7], k = 3
Output: 30.66667
Explanation: We pay 4 to 0th worker, 13.33333 to 2nd and 3rd workers separately.
Constraints:
n == quality.length == wage.length1 <= k <= n <= 1041 <= quality[i], wage[i] <= 104
Code and Explanation
- Greedy choice: Sort workers by
wage/qualityratio (the group rate). For each worker as the rate-setter, keep thekworkers with smallest quality sum via a max-heap. - Why it works: In any valid group, all pay =
ratio × qualitywhereratio = max(wage_i/quality_i). Fixing the max ratio worker and greedily picking smallest qualities minimizesratio × Σquality. - Sliding window of size
kover sorted ratios.
Time: O(n log n) | Space: O(n)
- Check every
k-subset; group ratio = max of member ratios. - O(C(n,k)·k) — greedy ratio-sort + heap is the intended solution.
Time: O(C(n,k) · k) | Space: O(k)
Problem 6: Reorganize String (Leetcode:767)#
Problem Statement
Given a string s, rearrange the characters of s so that any two adjacent characters are not the same.
Return any possible rearrangement of s or return "" if not possible.
Example 1:
Input: s = "aab" Output: "aba"
Example 2:
Input: s = "aaab" Output: ""
Constraints:
1 <= s.length <= 500sconsists of lowercase English letters.
Code and Explanation
- Greedy choice: Always place the most frequent remaining character, but not twice in a row — hold the previous char in a 1-step cooldown.
- Why it works: If
max_count <= (n+1)/2, scheduling most-frequent-first with spacing never dead-ends. Failing condition: one char dominates (max_count > (n+1)/2). - Equivalent to LC 767 / task scheduling with cooldown=1.
Time: O(n log 26) | Space: O(26)
- Fill even indices first (0,2,4,…), then odd — most frequent chars spread maximally.
- Same feasibility check; no heap needed.
- Greedy placement avoids adjacent duplicates by construction.
Time: O(n log 26) | Space: O(n)
8. Greedy + Two Pointers#
Advance two pointers greedily to solve sorted-array-based problems.
Problem 1: Assign Cookies (Leetcode:455)#
Problem Statement
Assume you are an awesome parent and want to give your children some cookies. But, you should give each child at most one cookie.
Each child i has a greed factor g[i], which is the minimum size of a cookie that the child will be content with; and each cookie j has a size s[j]. If s[j] >= g[i], we can assign the cookie j to the child i, and the child i will be content. Your goal is to maximize the number of your content children and output the maximum number.
Example 1:
Input: g = [1,2,3], s = [1,1]
Output: 1
Explanation: You have 3 children and 2 cookies. The greed factors of 3 children are 1, 2, 3.
And even though you have 2 cookies, since their size is both 1, you could only make the child whose greed factor is 1 content.
You need to output 1.
Example 2:
Input: g = [1,2], s = [1,2,3]
Output: 2
Explanation: You have 2 children and 3 cookies. The greed factors of 2 children are 1, 2.
You have 3 cookies and their sizes are big enough to gratify all of the children,
You need to output 2.
Constraints:
1 <= g.length <= 3 * 1040 <= s.length <= 3 * 1041 <= g[i], s[j] <= 231 - 1
Note: This question is the same as 2410: Maximum Matching of Players With Trainers.
Code and Explanation
- Greedy choice: Sort greed factors and cookie sizes. Give the smallest sufficient cookie to the least greedy unsatisfied child.
- Why it works: Using a larger cookie on a less greedy child wastes capacity — if
s[j] >= g[i], matching childinever reduces the count vs saving the cookie. Advancing cookie always (whether or not it satisfies) preserves options. - Maximize satisfied children, not minimize wasted cookies.
Time: O(m log m + n log n) | Space: O(1)
- For each child (sorted by greed), find the smallest unused fitting cookie.
- Same greedy logic but O(n·m) — two pointers after sorting is optimal.
Time: O(n · m) | Space: O(m)
Problem 2: Boats to Save People (Leetcode:881)#
Problem Statement
You are given an array people where people[i] is the weight of the ith person, and an infinite number of boats where each boat can carry a maximum weight of limit. Each boat carries at most two people at the same time, provided the sum of the weight of those people is at most limit.
Return the minimum number of boats to carry every given person.
Example 1:
Input: people = [1,2], limit = 3
Output: 1
Explanation: 1 boat (1, 2)
Example 2:
Input: people = [3,2,2,1], limit = 3
Output: 3
Explanation: 3 boats (1, 2), (2) and (3)
Example 3:
Input: people = [3,5,3,4], limit = 5
Output: 4
Explanation: 4 boats (3), (3), (4), (5)
Constraints:
1 <= people.length <= 5 * 1041 <= people[i] <= limit <= 3 * 104
Code and Explanation
- Greedy choice: Sort weights. Try pairing lightest with heaviest; if they don't fit, the heavy person goes alone.
- Why it works: The heaviest person must be rescued eventually — pairing them with the lightest wastes minimum capacity. If the pair doesn't fit, no one can pair with the heaviest, so they sail alone.
- Each iteration removes at least one person from consideration.
Time: O(n log n) | Space: O(1)
- State
(i,j)= range of unsaved people after sorting. - Same greedy decisions encoded recursively — exponential without memo on large n.
- Two-pointer greedy is O(n log n) and correct.
Time: O(n²) with memo | Space: O(n²)
Problem 3: Maximum Bags With Full Capacity of Rocks (Leetcode:2279)#
Problem Statement
You have n bags numbered from 0 to n - 1. You are given two 0-indexed integer arrays capacity and rocks. The ith bag can hold a maximum of capacity[i] rocks and currently contains rocks[i] rocks. You are also given an integer additionalRocks, the number of additional rocks you can place in any of the bags.
Return the maximum number of bags that could have full capacity after placing the additional rocks in some bags.
Example 1:
Input: capacity = [2,3,4,5], rocks = [1,2,4,4], additionalRocks = 2
Output: 3
Explanation:
Place 1 rock in bag 0 and 1 rock in bag 1.
The number of rocks in each bag are now [2,3,4,4].
Bags 0, 1, and 2 have full capacity.
There are 3 bags at full capacity, so we return 3.
It can be shown that it is not possible to have more than 3 bags at full capacity.
Note that there may be other ways of placing the rocks that result in an answer of 3.
Example 2:
Input: capacity = [10,2,2], rocks = [2,2,0], additionalRocks = 100
Output: 3
Explanation:
Place 8 rocks in bag 0 and 2 rocks in bag 2.
The number of rocks in each bag are now [10,2,2].
Bags 0, 1, and 2 have full capacity.
There are 3 bags at full capacity, so we return 3.
It can be shown that it is not possible to have more than 3 bags at full capacity.
Note that we did not use all of the additional rocks.
Constraints:
n == capacity.length == rocks.length1 <= n <= 5 * 1041 <= capacity[i] <= 1090 <= rocks[i] <= capacity[i]1 <= additionalRocks <= 109
Code and Explanation
- Greedy choice: Sort bags by rocks still needed (
capacity - rocks). Fill the cheapest bags first. - Why it works: Each full bag costs a fixed deficit; minimizing cost per bag maximizes count for a fixed rock budget (knapsack with equal unit value per completed bag).
- Stop when
additionalRocksis insufficient.
Time: O(n log n) | Space: O(1)
- Repeatedly fill the bag needing fewest additional rocks (min-heap).
- Same greedy policy as sorting — pick globally smallest remaining need each step.
Time: O(n log n) | Space: O(n)
9. Greedy on Graphs#
Graph algorithms that use greedy strategies (e.g., MSTs).
Problem 1: Prim's Algorithm (GeeksforGeeks)#
Problem Statement
Given a connected, weighted, undirected graph, find a Minimum Spanning Tree (MST) — a subset of edges connecting all vertices with minimum total weight.
Example 1:
Input: V=4, edges = [(0,1,10),(0,2,6),(0,3,5),(1,3,15),(2,3,4)]
Output: MST weight = 19 (edges: 2-3, 0-3, 0-1)
Example 2:
Input: V=3, edges = [(0,1,1),(1,2,2),(0,2,3)]
Output: 3
Constraints:
1 <= V <= 1041 <= E <= 105
Code and Explanation
- Greedy choice: Grow the MST from a start vertex; always add the cheapest edge crossing the cut (tree ↔ non-tree).
- Why it works: Cut property — the minimum-weight edge across any cut belongs to some MST. Prim's repeatedly applies this safe-edge rule.
- Min-heap tracks frontier edges.
Time: O(E log V) | Space: O(V + E)
- Prim grows one connected component; Kruskal sorts all edges — both greedy, different data structures.
- Use Prim for dense graphs, Kruskal for sparse.
Time: — | Space: —
Problem 2: Kruskal's Algorithm (GeeksforGeeks)#
Problem Statement
Given a connected, weighted, undirected graph, find an MST by selecting edges in ascending weight order without forming cycles.
Example 1:
Input: V=4, edges = [(0,1,10),(0,2,6),(0,3,5),(1,3,15),(2,3,4)]
Output: MST weight = 19
Example 2:
Input: V=5, edges = [(0,1,2),(1,2,3),(0,3,6),(3,4,5),(1,4,4)]
Output: 14
Constraints:
1 <= V <= 1041 <= E <= 105
Code and Explanation
- Greedy choice: Process edges in ascending weight; add an edge if it connects two different components (Union-Find).
- Why it works: Same cut-property / safe-edge theorem — the globally cheapest non-cycle edge is always safe.
- Stop after
V-1edges.
Time: O(E log E) | Space: O(V)
Problem 3: Network Delay Time (Leetcode:743)#
Problem Statement
You are given a network of n nodes, labeled from 1 to n. You are also given times, a list of travel times as directed edges times[i] = (ui, vi, wi), where ui is the source node, vi is the target node, and wi is the time it takes for a signal to travel from source to target.
We will send a signal from a given node k. Return the minimum time it takes for all the n nodes to receive the signal. If it is impossible for all the n nodes to receive the signal, return -1.
Example 1:
Input: times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
Output: 2
Example 2:
Input: times = [[1,2,1]], n = 2, k = 1
Output: 1
Example 3:
Input: times = [[1,2,1]], n = 2, k = 2
Output: -1
Constraints:
1 <= k <= n <= 1001 <= times.length <= 6000times[i].length == 31 <= ui, vi <= nui != vi0 <= wi <= 100- All the pairs
(ui, vi)are unique. (i.e., no multiple edges.)
Code and Explanation
- Greedy choice: Always settle the unvisited node with smallest tentative distance (Dijkstra).
- Why it works: With non-negative weights, the first time a node is extracted its distance is final — no cheaper path can exist (greedy stays ahead of all unprocessed nodes).
- Answer = max shortest-path distance from
kto all nodes.
Time: O(E log V) | Space: O(V + E)
- Relax all edges
n-1times — handles negative weights (not needed here). - O(V·E) vs Dijkstra's O(E log V); Dijkstra's greedy choice exploits non-negative edges.
Time: O(n · E) | Space: O(n)
Problem 4: Minimum Cost to Connect All Points (Leetcode:1584)#
Problem Statement
You are given an array points representing integer coordinates of some points on a 2D-plane, where points[i] = [xi, yi].
The cost of connecting two points [xi, yi] and [xj, yj] is the manhattan distance between them: |xi - xj| + |yi - yj|, where |val| denotes the absolute value of val.
Return the minimum cost to make all points connected. All points are connected if there is exactly one simple path between any two points.
Example 1:
Input: points = [[0,0],[2,2],[3,10],[5,2],[7,0]]
Output: 20
Explanation:
We can connect the points as shown above to get the minimum cost of 20.
Notice that there is a unique path between every pair of points.
Example 2:
Input: points = [[3,12],[-2,5],[-4,1]]
Output: 18
Constraints:
1 <= points.length <= 1000-106 <= xi, yi <= 106- All pairs
(xi, yi)are distinct.
Code and Explanation
- Greedy choice: Complete graph on points with Manhattan edge weights — grow MST via Prim, always adding the cheapest edge to an unvisited point.
- Why it works: MST cut property applies to any connected graph; Manhattan metric doesn't change the greedy safe-edge argument.
- O(n² log n) acceptable for n ≤ 1000.
Time: O(n² log n) | Space: O(n)
- Generate all
C(n,2)edges, sort by weight, Union-Find merge. - Same MST weight as Prim — dual greedy strategy.
- O(n² log n) from edge generation and sort.
Time: O(n² log n) | Space: O(n²)


