Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

For example,
If n = 4 and k = 2, a solution is:

[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

这道题让求1到n共n个数字里k个数的组合数的所有情况,还是要用深度优先搜索DFS来解,根据以往的经验,像这种要求出所有结果的集合,一般都是用DFS调用递归来解。那么我们建立一个保存最终结果的大集合res,还要定义一个保存每一个组合的小集合out,每次放一个数到out里,如果out里数个数到了k个,则把out保存到最终结果中,否则在下一层中继续调用递归。网友u010500263的博客里有一张图很好的说明了递归调用的顺序,请点击这里。根据上面分析,可写出代码如下:

解法一:

class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> res;
vector<int> out;
helper(n, k, , out, res);
return res;
}
void helper(int n, int k, int level, vector<int>& out, vector<vector<int>>& res) {
if (out.size() == k) {res.push_back(out); return;}
for (int i = level; i <= n; ++i) {
out.push_back(i);
helper(n, k, i + , out, res);
out.pop_back();
}
}
};

对于n = 5, k = 3, 处理的结果如下:

1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5

我们再来看一种递归的写法,此解法没用helper当递归函数,而是把本身就当作了递归函数,写起来十分的简洁,也是非常有趣的一种解法。这个解法用到了一个重要的性质 C(n, k) = C(n-1, k-1) + C(n-1, k),这应该在我们高中时候学排列组合的时候学过吧,博主也记不清了。总之,翻译一下就是,在n个数中取k个数的组合项个数,等于在n-1个数中取k-1个数的组合项个数再加上在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]。我们发现二者加起来为6,正好是 C(4, 2) 的个数之和。但是我们仔细看会发现,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 的所有情况了。参见代码如下:

解法二:

class Solution {
public:
vector<vector<int>> combine(int n, int k) {
if (k > n || k < ) return {};
if (k == ) return {{}};
vector<vector<int>> res = combine(n - , k - );
for (auto &a : res) a.push_back(n);
for (auto &a : combine(n - , k)) res.push_back(a);
return res;
}
};

我们再来看一种迭代的写法,也是一种比较巧妙的方法。这里每次先递增最右边的数字,存入结果res中,当右边的数字超过了n,则增加其左边的数字,然后将当前数组赋值为左边的数字,再逐个递增,直到最左边的数字也超过了n,停止循环。对于n=4, k=2时,遍历的顺序如下所示:

0 0 #initialization
1 0
1 1
1 2 #push_back
1 3 #push_back
1 4 #push_back
1 5
2 5
2 2
2 3 #push_back
2 4 #push_back
...
3 4 #push_back
3 5
4 5
4 4
4 5
5 5 #stop

解法三:

class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> res;
vector<int> out(k, );
int i = ;
while (i >= ) {
++out[i];
if (out[i] > n) --i;
else if (i == k - ) res.push_back(out);
else {
++i;
out[i] = out[i - ];
}
}
return res;
}
};

类似题目:

Combination Sum

Permutations

参考资料:

https://leetcode.com/problems/combinations/description/

https://leetcode.com/problems/combinations/discuss/27015/3-ms-Java-Solution

https://leetcode.com/problems/combinations/discuss/27002/Backtracking-Solution-Java

https://leetcode.com/problems/combinations/discuss/26992/Short-Iterative-C++-Answer-8ms

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Combinations 组合项的更多相关文章

  1. [FollowUp] Combinations 组合项

    这是Combinations 组合项 的延伸,在这里,我们允许不同的顺序出现,那么新的题目要求如下: Given two integers n and k, return all possible c ...

  2. [Leetcode] combinations 组合

    Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. For exampl ...

  3. LeetCode:组合总数III【216】

    LeetCode:组合总数III[216] 题目描述 找出所有相加之和为 n 的 k 个数的组合.组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字. 说明: 所有数字都是正整数. ...

  4. LeetCode:组合总数II【40】

    LeetCode:组合总数II[40] 题目描述 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candi ...

  5. 【LeetCode每天一题】Combinations(组合)

    Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. Example: I ...

  6. leetCode 77.Combinations (组合)

    Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. For exampl ...

  7. [leetcode]77. Combinations组合

    Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. Example: I ...

  8. LeetCode 77. 组合(Combinations)

    题目描述 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合. 示例: 输入: n = 4, k = 2 输出: [ [2,4], [3,4], [2,3], [1,2], ...

  9. LeetCode——Combinations

    Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. For exampl ...

随机推荐

  1. awk使用说明

    原文地址:http://www.cnblogs.com/verrion/p/awk_usage.html Awk使用说明 运维必须掌握的三剑客工具:grep(文件内容过滤器),sed(数据流处理器), ...

  2. WPF binding 参考

    Introduction This is an article on WPF Binding Cheat Sheet. Some of the Binding won't work for Silve ...

  3. spring笔记6 spring IOC的中级知识

    1,spring ioc的整体流程,xml配置 spring ioc初始化的流程结合上图 步骤编号 完成的工作 1 spring容器读取配置文件,解析称注册表 2 根据注册表,找到相应的bean实现类 ...

  4. php:ci学习笔记1

    ci下载的开发包:     phpstudy的部署: phpstudy的根目录是:D:\WWW 新建目录 cms  把ci开发包的application   system index.php  lic ...

  5. Yii2.X 多语言-类图

  6. PHP 策略模式

    策略模式:定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化.策略模式把对象本身和运算规则区分开来,其功能非常强大,因为这个设计模式本身的核心思想 ...

  7. Idea SpringMVC+Spring+MyBatis+Maven调整【转】

    Idea SpringMVC+Spring+MyBatis+Maven整合   创建项目 File-New Project 选中左侧的Maven,选中右侧上方的Create from archetyp ...

  8. 弹出层layer的使用

    弹出层layer的使用 Intro layer是一款web弹层组件,致力于服务各个水平段的开发人员.layer官网:http://layer.layui.com/ layer侧重于用户灵活的自定义,为 ...

  9. iOS 报错汇总

    1. Unknown type name 'class'; did you mean 'Class' 问题解决方法 objectice-c 工程中的类(比如 类 A)使用 C++ 文件时  A.m 文 ...

  10. Javascript不同浏览器差异及兼容方法

    原文链接:http://caibaojian.com/js-ie-different-from-firefox.html javascript的各种兼容就是为了解决不同浏览器的差异性,了解其中的差异能 ...