Smallest Subset with Sum Greater than the Rest is a clean greedy warm-up. It teaches the core greedy instinct: when you want a goal with the fewest pieces, grab the most powerful piece available at every step.
Problem. Given an array of positive integers nums, choose a subset whose sum is strictly greater
than the sum of the numbers left behind. Return the minimum number of elements such a subset can have.
Example: nums = [9, 5, 4, 3, 1] (total = 22) → answer 2, because 9 + 5 = 14 already beats the
remaining 4 + 3 + 1 = 8.
The slow way first
The brute-force idea: try every possible subset, check which ones have a sum greater than the rest, and keep the smallest. There are 2^n subsets, so this is exponential — hopeless for anything but tiny arrays.
The question to ask: if I am allowed only a fixed number of elements, how do I make their sum as large as possible? Obviously, pick the largest elements. So for a subset of any given size, the best possible sum uses the biggest numbers. That observation collapses the whole search.
The idea: grab the biggest, count as you go
Sort the array in descending order. Walk it from the front, adding each number to a running chosen sum. After each grab, compare chosen against the leftover rest = total - chosen. The moment chosen strictly exceeds rest, we are done — and because we always took the largest available numbers, no smaller subset could have reached that point.
The key insight: taking the largest remaining number each time grows chosen the fastest and shrinks rest the fastest, so we cross the line in the fewest possible steps.
Walk through it
Step through the animation. After sorting we have [9, 5, 4, 3, 1] with total 22. Take 9: chosen = 9, rest = 13 — not enough yet. Take 5: chosen = 14, rest = 8 — now 14 > 8, so we stop. The smallest subset is {9, 5}, just 2 elements.
Pseudocode
total = sum of all numbers
sort the numbers from largest to smallest
chosen = 0
for each number x in sorted order, counting from 1:
chosen = chosen + x
if chosen > total - chosen: # chosen beats the leftover
return the current count
return the count of all numbers # (only if no strict majority is possible)The Python solution
def min_subset(nums):
total = sum(nums)
nums.sort(reverse=True)
chosen = 0
for count, x in enumerate(nums, start=1):
chosen += x
if chosen > total - chosen:
return count
return len(nums)totalis the sum of everything, computed once so we can deriverestcheaply.nums.sort(reverse=True)puts the largest numbers first — the heart of the greedy choice.enumerate(nums, start=1)gives both a runningcountand the valuex, socountis already the subset size.chosen += xgrows our running sum with the biggest available number.- Line 7 is the test:
chosen > total - chosenis the same aschosenbeating the leftoverrest. The first time it holds,countis the answer.
Complexity
| Case | Time | Notes |
|---|---|---|
| Brute force (all subsets) | O(2^n) (slow) | checks every subset |
| Greedy (this solution) | O(n log n) (moderate) | sort dominates the scan |
O(1) (fast)The sort costs O(n log n) and the single pass is O(n), so the sort dominates. We use only a couple of accumulator variables, so extra space is O(1) (ignoring the sort).
When this pattern shows up
When a problem asks for the fewest items to reach some threshold (or the most value within a budget), suspect greedy: sort by the dimension that matters and take from the strong end. Prove it works by an exchange argument — swapping in a larger element never hurts.
Read the comparison carefully: the requirement is usually strictly greater, not greater-or-equal. With
an even split like [1, 1], neither half is strictly greater than the other until you take both, so the
boundary case matters.
Practice
For nums = [9, 5, 4, 3, 1] (total 22), after taking 9 then 5, what are chosen and rest, and do we stop?
1. Why does sorting descending give the smallest subset?
2. What condition tells us to stop?
3. What is the dominant time cost of the solution?
4. Why must the comparison be strictly greater rather than greater-or-equal?