You are given two integers n and k, return all possible combinations of k numbers chosen from the range [1, n].
You may return the answer in any order.
Example 1:
Input: n = 3, k = 2
Output: [
[1,2],
[1,3],
[2,3]
]Example 2:
Input: n = 3, k = 3
Output: [[1,2,3]]Constraints:
1 <= k <= n <= 20To generate all combinations of k numbers from 1 to n, we make a binary choice for each number: include it or exclude it. This forms a decision tree where each path represents a subset. We only keep subsets of exactly size k.
i = 1.i in the combination, or skip it.i.i exceeds n, check if the combination has exactly k elements. If so, add a copy to the result.class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
res = []
def backtrack(i, comb):
if i > n:
if len(comb) == k:
res.append(comb.copy())
return
comb.append(i)
backtrack(i + 1, comb)
comb.pop()
backtrack(i + 1, comb)
backtrack(1, [])
return resWhere is the number of elements and is the number of elements to be picked.
Instead of making include/exclude decisions, we iterate through available numbers and always include one. Starting from a given position ensures we never revisit smaller numbers, avoiding duplicates. We stop when the combination reaches size k.
1.k, save a copy to the result and return.n. For each number, add it to the combination.start = i + 1 to only consider larger numbers.class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
res = []
def backtrack(start, comb):
if len(comb) == k:
res.append(comb.copy())
return
for i in range(start, n + 1):
comb.append(i)
backtrack(i + 1, comb)
comb.pop()
backtrack(1, [])
return resWhere is the number of elements and is the number of elements to be picked.
We can simulate backtracking iteratively using an array of size k to track our current combination. An index pointer moves forward when we find valid numbers and backward when we need to backtrack. This eliminates recursion overhead.
k with zeros and a pointer i = 0.comb[i] to try the next value at position i.comb[i] exceeds n, move the pointer back (i -= 1) to backtrack.i reaches k - 1, we have a complete combination; save it.i += 1) and set comb[i] = comb[i - 1] so the next position starts just after the previous value.i becomes negative.Where is the number of elements and is the number of elements to be picked.
Each subset of numbers from 1 to n can be represented as an n-bit binary number, where bit i being set means number (i+1) is included. We iterate through all possible bitmasks and keep only those with exactly k bits set.
0 to 2^n - 1. Each integer represents a possible subset.j is set, include j + 1).k elements, add it to the result.Where is the number of elements and is the number of elements to be picked.
When adding the current combination to the result list, you must create a copy. Otherwise, subsequent modifications during backtracking will alter the already-added result.
# Wrong: adds reference that gets modified
res.append(comb)
# Correct: adds a copy
res.append(comb.copy())After exploring a branch with an element included, you must remove it before exploring the next branch. Forgetting to pop leads to combinations with too many elements.
comb.append(i)
backtrack(i + 1, comb)
# Missing: comb.pop()Starting the loop at 0 instead of start causes duplicate combinations like [1,2] and [2,1]. The loop must start from the current position to ensure each combination is generated only once in sorted order.