题目: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], ]
思路:回溯法+动态规划
更加推荐第一种解法。第二种实在没有能够理解。以后的回溯法尽量使用本模型。
我将本答案的解法过程一一列举,应该能够容易理解。
进入第二个循环的时候,先是进入2,进入第三个循环,发现满了,保存,返回,退出,继续进入3,以此类推。
1,2,– 1,3 — 1,4 — …
第二种方法是:用answer中的长度作为结束条件,还有一个条件就是写入的值不能大于n,这个是第二条件了。
不过在最后,要加上combineHelper(n,k,start+1,answer,result);不然只是求解了一个插入首字母的结果。
不过,这不是最完美的回溯法的典型程序,可以参考我之后的求解和的程序。
代码:
class Solution1 { public: void combineHelper(int n,int k,int start,vector<int> &answer,vector<vector<int> >&result){ if(answer.size()==k){ result.push_back(answer); return; } //answer暂时保存k位数字 if(answer.size()>k){//节省不必要浪费时间 return; } for(int i=start;i<=n;i++){ answer.push_back(i); combineHelper(n,k,i+1,answer,result); answer.pop_back(); } //虽然这边写的是删除一个值,但是因为是迭代,所以第一个函数运行到这边的时候, //实际相当于把第一次的一整个vector清空,验证这个可以通过把下面的那个语句屏蔽到 //发现只能生成一组vector。 //这个程序谨记,第一次遇到。 //所以下面的值为start+1,而不是start+2. } vector<vector<int> > combine(int n, int k) { vector<vector<int> >result; vector<int>answer; combineHelper(n,k,1,answer,result); return result; } };
class Solution2 { public: void combineHelper(int n,int k,int start,vector<int> &answer,vector<vector<int> >&result){ if(answer.size()==k){ result.push_back(answer); return; } //answer暂时保存k位数字 if(start>n){ return; } answer.push_back(start); combineHelper(n,k,start+1,answer,result); answer.pop_back(); //虽然这边写的是删除一个值,但是因为是迭代,所以第一个函数运行到这边的时候, //实际相当于把第一次的一整个vector清空,验证这个可以通过把下面的那个语句屏蔽到 //发现只能生成一组vector。 //这个程序谨记,第一次遇到。 //所以下面的值为start+1,而不是start+2. combineHelper(n,k,start+1,answer,result); } vector<vector<int> > combine(int n, int k) { vector<vector<int> >result; vector<int>answer; combineHelper(n,k,1,answer,result); return result; } };