Given two integers n and k, return all possible combinations ofknumbers chosen from the range[1, n].
You may return the answer in any order.
Example 1:
Input: n = 4, k = 2
Output: [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
Explanation: There are 4 choose 2 = 6 total combinations.
Note that combinations are unordered, i.e., [1,2] and [2,1] are considered to be the same combination.
Example 2:
Input: n = 1, k = 1
Output: [[1]]
Explanation: There is 1 choose 1 = 1 total combination.
Constraints:
1 <= n <= 20
1 <= k <= n
Solutions
Solution 1: Backtracking (Two Ways)
Thinking
The first idea is all \(2^n\) subsets of \(\{1,\ldots,n\}\), keep those of length \(k\). \(n \le 20\) might pass, but most subsets have the wrong size.
Order does not matter; each number is in or out, and we can stop a path once its length is \(k\). So \(dfs(i)\) handles \(i\): push, recurse \(i+1\), pop, then skip. Enumerating the next \(j\) among leftovers is the other tree; both yield the same combinations. The code below is the first form.
We design a function \(dfs(i)\), which represents starting the search from number \(i\), with the current search path as \(t\), and the answer as \(ans\).
The execution logic of the function \(dfs(i)\) is as follows:
If the length of the current search path \(t\) equals \(k\), then add the current search path to the answer and return.
If \(i \gt n\), it means the search has ended, return.
Otherwise, we can choose to add the number \(i\) to the search path \(t\), and then continue the search, i.e., execute \(dfs(i + 1)\), and then remove the number \(i\) from the search path \(t\); or we do not add the number \(i\) to the search path \(t\), and directly execute \(dfs(i + 1)\).
The above method is actually enumerating whether to select the current number or not, and then recursively searching the next number. We can also enumerate the next number \(j\) to be selected, where \(i \leq j \leq n\). If the next number to be selected is \(j\), then we add the number \(j\) to the search path \(t\), and then continue the search, i.e., execute \(dfs(j + 1)\), and then remove the number \(j\) from the search path \(t\).
In the main function, we start the search from number \(1\), i.e., execute \(dfs(1)\).
The time complexity is \((C_n^k \times k)\), and the space complexity is \(O(k)\). Here, \(C_n^k\) represents the combination number.
Method 1 walks a choose/skip tree of depth \(n\); skip branches still scan the rest of the numbers. Method 2 enumerates the next chosen \(j \in [i,n]\), so recursion depth equals how many we have picked, and the tree matches combinations of length \(k\) more closely. Same answers; the loop just expands the remaining candidates.