# [77. Combinations](https://leetcode.com/problems/combinations/)
# 思路
给定n和k，问从1、2、...、n这n个数中选k个不同的数的所有选法，返回这些选法。

## 思路一、DFS
**常规思路，务必掌握！**             
像这种要求出所有结果的集合，一般都是用DFS调用递归来解。
我们建立一个保存最终结果的大集合res，还要定义一个保存每一个组合的小集合cb，每次放一个数到cb里，如果cb里数个数到了k个，则把cb保存到最终结果res中，否则在下一层中继续调用递归。

## 思路二
我们再来看一种递归的写法，此解法没用helper当递归函数，而是把本身就当作了递归函数，写起来十分的简洁。
这个解法用到了高中学的一个排列组合的性质:`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 helper(vector<vector<int>> &res, vector<int> &cb, const int level, const int n, const  int k){
        if(cb.size() == k){
            res.push_back(cb);
            return;
        }
        for(int i = level; i <= n; i++){
            cb.push_back(i);
            helper(res, cb, i + 1, n, k);
            cb.pop_back();
        }
    }
public:
    vector<vector<int>> combine(int n, int k) {
        vector<vector<int>>res;
        vector<int>cb;
        if(n < k) return res;
        helper(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;
    }
};
```
