77. Combinations
leetcode medium
Task
Даны два целых числа n и k. Верните все возможные комбинации из k чисел, выбранных из диапазона [1, n].
Ответ можно вернуть в любом порядке.
Пример:
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.
C# solution
matched/originalpublic class Solution {
private int n;
private int k;
public IList<IList<int>> Combine(int n, int k) {
this.n = n;
this.k = k;
List<List<int>> ans = new List<List<int>>();
Backtrack(new List<int>(), 1, ans);
return ans.Cast<IList<int>>().ToList();
}
public void Backtrack(List<int> curr, int firstNum, List<List<int>> ans) {
if (curr.Count == k) {
ans.Add(new List<int>(curr));
return;
}
int need = k - curr.Count;
int remain = n - firstNum + 1;
int available = remain - need;
for (int num = firstNum; num <= firstNum + available; num++) {
curr.Add(num);
Backtrack(curr, num + 1, ans);
curr.RemoveAt(curr.Count - 1);
}
}
}C++ solution
auto-draft, review before submit#include <bits/stdc++.h>
using namespace std;
// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
class Solution {
public:
private int n;
private int k;
public IList<vector<int>> Combine(int n, int k) {
this.n = n;
this.k = k;
List<List<int>> ans = new List<List<int>>();
Backtrack(new List<int>(), 1, ans);
return ans.Cast<vector<int>>().ToList();
}
public void Backtrack(List<int> curr, int firstNum, List<List<int>> ans) {
if (curr.size() == k) {
ans.push_back(new List<int>(curr));
return;
}
int need = k - curr.size();
int remain = n - firstNum + 1;
int available = remain - need;
for (int num = firstNum; num <= firstNum + available; num++) {
curr.push_back(num);
Backtrack(curr, num + 1, ans);
curr.RemoveAt(curr.size() - 1);
}
}
}Java solution
matched/originalclass Solution {
private int n;
private int k;
public List<List<Integer>> combine(int n, int k) {
this.n = n;
this.k = k;
List<List<Integer>> ans = new ArrayList<>();
backtrack(new ArrayList<>(), 1, ans);
return ans;
}
public void backtrack(
List<Integer> curr,
int firstNum,
List<List<Integer>> ans
) {
if (curr.size() == k) {
ans.add(new ArrayList<>(curr));
return;
}
int need = k - curr.size();
int remain = n - firstNum + 1;
int available = remain - need;
for (int num = firstNum; num <= firstNum + available; num++) {
curr.add(num);
backtrack(curr, num + 1, ans);
curr.remove(curr.size() - 1);
}
}
}JavaScript solution
matched/originalvar combine = function (n, k) {
const ans = [];
const backtrack = (curr, firstNum) => {
if (curr.length === k) {
ans.push([...curr]);
return;
}
const need = k - curr.length;
const remain = n - firstNum + 1;
const available = remain - need;
for (let num = firstNum; num <= firstNum + available; num++) {
curr.push(num);
backtrack(curr, num + 1);
curr.pop();
}
};
backtrack([], 1);
return ans;
};Python solution
matched/originalclass Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
def backtrack(curr, first_num):
if len(curr) == k:
ans.append(curr[:])
return
need = k - len(curr)
remain = n - first_num + 1
available = remain - need
for num in range(first_num, first_num + available + 1):
curr.append(num)
backtrack(curr, num + 1)
curr.pop()
ans = []
backtrack([], 1)
return ansGo solution
matched/originalfunc combine(n int, k int) [][]int {
var ans [][]int
var curr []int
var backtrack func(int)
backtrack = func(firstNum int) {
if len(curr) == k {
ans = append(ans, append([]int{}, curr...))
return
}
need := k - len(curr)
remain := n - firstNum + 1
available := remain - need
for num := firstNum; num <= firstNum+available; num++ {
curr = append(curr, num)
backtrack(num + 1)
curr = curr[:len(curr)-1]
}
}
backtrack(1)
return ans
}Explanation
Algorithm
1️⃣
Инициализировать массив ответов ans и массив для построения комбинаций curr.
2️⃣
Создать функцию обратного вызова backtrack, которая принимает curr в качестве аргумента, а также целое число firstNum:
Если длина curr равна k, добавить копию curr в ans и вернуться.
Вычислить available, количество чисел, которые мы можем рассмотреть в текущем узле.
Итерировать num от firstNum до firstNum + available включительно.
Для каждого num, добавить его в curr, вызвать backtrack(curr, num + 1), а затем удалить num из curr.
3️⃣
Вызвать backtrack с изначально пустым curr и firstNum = 1.
Вернуть ans.
😎