LeetCode/solutions/77. Combinations.md
2020-06-22 21:24:57 +08:00

59 lines
3.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# [77. Combinations](https://leetcode.com/problems/combinations/)
# 思路
给定n和k问从1、2、...、n这n个数中选k个不同的数的所有选法返回这些选法。
## 思路一、DFS
**常规思路,务必掌握!**
像这种要求出所有结果的集合一般都是用DFS调用递归来解。
我们建立一个保存最终结果的大集合res还要定义一个保存每一个组合的小集合cb每次放一个数到cb里如果cb里数个数到了k个则把cb保存到最终结果res中否则在下一层中继续调用递归。
## 思路二
我们再来看一种递归的写法,此解法没额外定义递归函数,而是把本身就当作了递归函数,写起来十分的简洁。
这个解法用到了高中学的一个排列组合的性质:`C(n, k) = C(n-1, k-1) + C(n-1, k)`在n个数中取k个数的组合项个数等于在n-1个数中取k-1个数的组合项个数再加上在n-1个数中取k个数的组合项个数之和。
证明也很容易因为取得的k个数可以分成两类第一类是包含最后一个数那么只需要在前n-1个数中再选k-1个数出来就行了故这一类一共有`C(n-1, k-1)`种第二类是不包含最后一个数那么需要在前n-1个数中选k个数出来故这一类一共有`C(n-1, k)`种。所以一共就是`C(n, k) = C(n-1, k-1) + C(n-1, k)`种。
对于题目中的例子,我们有`C(4, 2) = C(3, 1) + C(3, 2)`, 我们不难写出 C(3, 1) 的所有情况:[1], [2], [3],还有 C(3, 2) 的所有情况:[1, 2], [1, 3], [2, 3]。我们仔细看会发现C(3, 2)的所有情况包含在 C(4, 2) 之中,但是 C(3, 1) 的每种情况只有一个数字而我们需要的结果k=2其实很好办每种情况后面都加上4于是变成了[1, 4], [2, 4], [3, 4]加上C(3, 2) 的所有情况:[1, 2], [1, 3], [2, 3],正好就得到了 n=4, k=2 的所有情况了。
需要注意的是:
* `if(k > n || k < 0)`时,`C(n, k) = 0`,此时所有的组合是一个空的二维数组;
* `if(k == 0)`时,`C(n, k) = 1`, 此时所有的组合是一个包含了1个空一维数组的二维数组注意与上一种情况的区别。
# C++
## 思路一
``` C++
class Solution {
private:
void DFS(vector<vector<int>> &res, vector<int> &cb, int start, int n, int k){
if(cb.size() == k){
res.push_back(cb);
return;
}
if(start > n) return;
DFS(res, cb, start + 1, n, k);
cb.push_back(start);
DFS(res, cb, start + 1, n, k);
cb.pop_back();
}
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>>res;
vector<int>cb;
DFS(res, cb, 1, n, k);
return res;
}
};
```
## 思路二
``` C++
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
if(k > n || k < 0) return vector<vector<int>>(); // 空的二维数组
if(k == 0) return vector<vector<int>>(1, vector<int>()); // 包含了1个空一维数组的二维数组
vector<vector<int>> res = combine(n - 1, k - 1);
for(int i = 0; i < res.size(); i++) res[i].push_back(n);
for(auto &cb: combine(n - 1, k)) res.push_back(cb);
return res;
}
};
```