【Combinations】cpp
题目:
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], ]
代码:
class Solution { public: vector<vector<int>> combine(int n, int k) { vector<vector<int> > ret; if ( n<k ) return ret; vector<int> tmp; Solution::dfs(ret, 1, k, n, 0,tmp); return ret; } static void dfs(vector<vector<int> >& ret, int index, int k, int n, int step, vector<int>& tmp) { if ( step==k ) { ret.push_back(tmp); return; } for ( size_t i = index; i <=n; ++i ) { tmp.push_back(i); Solution::dfs(ret, i+1, k, n, step+1, tmp); tmp.pop_back(); } } };
tips:
dfs解法。
几个参数的含义:
ret: 存储返回combination结果
index: 当前起始元素是多大
k,n:与题意所给相同
step:深入到第几层
思路:dfs的每层增加一个元素,直到深度等于k返回结果;如果从index开始的元素不足以打到深度k,则不会添加到ret中。
======================================
其实,可以不用传入6个参数,传入5个足以。代码如下:
class Solution { public: vector<vector<int>> combine(int n, int k) { vector<vector<int> > ret; if ( n<k ) return ret; vector<int> tmp; Solution::dfs(ret, 1, k, n, tmp); return ret; } static void dfs(vector<vector<int> >& ret, int index, int k, int n, vector<int>& tmp) { if ( tmp.size()==k ) { ret.push_back(tmp); return; } for ( size_t i = index; i <=n; ++i ) { tmp.push_back(i); Solution::dfs(ret, i+1, k, n, tmp); tmp.pop_back(); } } };
用tmp.size()代替step,代码跟简洁一些,因此更推崇后一种方法。
=======================================
leetcode写到这里有些感觉了,搜了一下dfs bfs的模板相关的内容,基本跟实战中的经验差不多:
http://blog.csdn.net/fightforyourdream/article/details/12866861
http://www.cnblogs.com/HectorInsanE/archive/2010/11/09/1872656.html
=======================================
再补上一种迭代的解法,如下:
class Solution { public: vector<vector<int>> combine(int n, int k) { vector<vector<int> > ret; // corner cases if ( n<k || k==0 ) return ret; // initialization for ( int i = 0; i < n-k+1; ++i ) { vector<int> tmp; tmp.push_back(i+1); ret.push_back(tmp); } // combines for ( int i = 0; i < k-1; ++i ) { vector<vector<int> > tmp = ret; ret.clear(); for ( int j = 0; j < tmp.size(); ++j ) { int curr = tmp[j].back(); for ( int v = curr+1; v <= n; ++v ) { vector<int> ori = tmp[j]; ori.push_back(v); ret.push_back(ori); } } } return ret; } };
tips:
1. 这种迭代方式返回的组合内部都是由小到大排序的。
2. intialization的含义是”组合首个元素最小到最大“(比如n=4,k=2 按照原则1,则首个元素最大取到3,因为比4小的元素没有了不足以满足k=2的条件)
3. 每轮迭代,先取出来当前组合最后一个元素(最大的)curr;再从curr+1到n挨个取值,补到tmp[j]的后面,构成新的组合。
4. 控制迭代的次数是k-1次(因为initialization已经算了一次)
===============================================
第二次过这道题,用dfs过的,传入参数比第一次过更简洁一些。
class Solution { public: vector<vector<int> > combine(int n, int k) { vector<vector<int> > ret; vector<int> tmp; Solution::dfs(ret, tmp, n, k); return ret; } static void dfs( vector<vector<int> >& ret, vector<int>& tmp, int n, int k) { if ( tmp.size()==k ) { ret.push_back(tmp); return; } int index = tmp.empty() ? 0 : tmp.back(); for ( int i=index+1; i<=n; ++i ) { tmp.push_back(i); Solution::dfs(ret, tmp, n, k); tmp.pop_back(); } } };