Combinations Problem
MediumUpdated: Aug 2, 2025
Practice on:
Problem
Given two integers n and k, return all possible combinations of k numbers out of the range [1, n].
You may return the answer in any order.
Examples
Example 1:
Input: n = 4, k = 2
Output:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
Example 2:
Input: n = 1, k = 1
Output: [[1]]
Solution
Method 1 – Backtracking (DFS)
Intuition
To generate all combinations of k numbers from 1 to n, we can use backtracking to build each combination step by step, exploring all possible choices at each step.
Approach
- Start with an empty combination and a starting number 1.
- At each step, add the next number to the current combination and recurse.
- If the combination reaches size k, add it to the answer.
- Backtrack by removing the last number and trying the next possible number.
Code
C++
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> ans;
vector<int> cur;
function<void(int)> dfs = [&](int start) {
if (cur.size() == k) { ans.push_back(cur); return; }
for (int i = start; i <= n; ++i) {
cur.push_back(i);
dfs(i+1);
cur.pop_back();
}
};
dfs(1);
return ans;
}
};
Go
func combine(n int, k int) [][]int {
var ans [][]int
var cur []int
var dfs func(int)
dfs = func(start int) {
if len(cur) == k {
tmp := make([]int, k)
copy(tmp, cur)
ans = append(ans, tmp)
return
}
for i := start; i <= n; i++ {
cur = append(cur, i)
dfs(i+1)
cur = cur[:len(cur)-1]
}
}
dfs(1)
return ans
}
Java
class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> cur = new ArrayList<>();
dfs(1, n, k, cur, ans);
return ans;
}
private void dfs(int start, int n, int k, List<Integer> cur, List<List<Integer>> ans) {
if (cur.size() == k) {
ans.add(new ArrayList<>(cur));
return;
}
for (int i = start; i <= n; i++) {
cur.add(i);
dfs(i+1, n, k, cur, ans);
cur.remove(cur.size()-1);
}
}
}
Kotlin
class Solution {
fun combine(n: Int, k: Int): List<List<Int>> {
val ans = mutableListOf<List<Int>>()
val cur = mutableListOf<Int>()
fun dfs(start: Int) {
if (cur.size == k) {
ans.add(cur.toList())
return
}
for (i in start..n) {
cur.add(i)
dfs(i+1)
cur.removeAt(cur.size-1)
}
}
dfs(1)
return ans
}
}
Python
class Solution:
def combine(self, n: int, k: int) -> list[list[int]]:
ans = []
cur = []
def dfs(start: int):
if len(cur) == k:
ans.append(cur[:])
return
for i in range(start, n+1):
cur.append(i)
dfs(i+1)
cur.pop()
dfs(1)
return ans
Rust
impl Solution {
pub fn combine(n: i32, k: i32) -> Vec<Vec<i32>> {
fn dfs(n: i32, k: i32, start: i32, cur: &mut Vec<i32>, ans: &mut Vec<Vec<i32>>) {
if cur.len() == k as usize {
ans.push(cur.clone());
return;
}
for i in start..=n {
cur.push(i);
dfs(n, k, i+1, cur, ans);
cur.pop();
}
}
let mut ans = vec![];
let mut cur = vec![];
dfs(n, k, 1, &mut cur, &mut ans);
ans
}
}
TypeScript
class Solution {
combine(n: number, k: number): number[][] {
const ans: number[][] = [];
const cur: number[] = [];
function dfs(start: number) {
if (cur.length === k) {
ans.push([...cur]);
return;
}
for (let i = start; i <= n; i++) {
cur.push(i);
dfs(i+1);
cur.pop();
}
}
dfs(1);
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(C(n, k) * k), where C(n, k) is the number of combinations. Each combination takes O(k) to build. - 🧺 Space complexity:
O(C(n, k) * k), for storing all combinations.