Generating all combinations
Build all k-element subsets of 1 to n in lexicographic order; each next item is larger than the last, so no subset comes twice.
So that no subset comes twice (in different orders), the items are kept increasing: after x, only items larger
than x are tried.
- Time:
O(k · C(n, k)) - Space:
O(k) - Johnsonbaugh, chapter 6
- Grimaldi, chapter 1
The 3-element subsets of 5 items: C(5, 3) = 10 combinations, from 123 to 345.
def combinations(n, k):current = []rows = []extend(1, n, k, current, rows)return len(rows)def extend(start, n, k, current, rows):if len(current) == k:rows.append(tuple(current))return# Leave room for the items still needed: the last start that can still complete a combination.last = n - (k - len(current)) + 1for x in range(start, last + 1):current.append(x)extend(x + 1, n, k, current, rows)current.pop()
Start
The table is still empty.
Recursion tree
Filled orange = running call · Orange outline = still on the stack · Grey = finished
Local variables
Orange = changed in this step
Call stack
- combinations()line 1
Explanation
The idea
So that no subset comes twice (in different orders), the items are kept increasing: after x, only items larger
than x are tried.
Pruning
If r more items are needed, starting above n − r + 1 is pointless, because not enough items would be left. With
this bound, every branch that opens reaches at least one combination.
Cost
C(n, k) = n! / (k! (n − k)!) combinations of k items each.
What to watch in the trace
- Compare the call tree with the "generating all permutations" page: here each level only tries larger numbers.