Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
典型的DFS,循环递归,典型的递归回溯法,多做形成这个递归回溯头脑,就好办了。
1 递归一次,填入一个数字
2 填入的数字,不能是小于当前数字的值,防止重复
3 回溯:记得pop_back()最后加上的一个数字,回溯到上一层。
4 结束条件:填写够了k个数字的时候,当前填写完毕,回溯
c++代码如下:
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int> > res;
vector<int> cur;
rec(res, cur, n, k, 1);
return res;
}
private:
void rec(vector<vector<int> > &res, vector<int> &cur,const int n, const int k, int m) {
if(cur.size() == k) {
res.push_back( cur );
return;
}
for(int i=m; i<=n; i++) {
cur.push_back( i );
rec(res, cur, n, k, i+1); //循环递归的过程比较复杂,需要认真理解
cur.pop_back();
}
}
};
java代码如下:
<pre name="code" class="java">public class Solution {
private List<List<Integer>> res = new ArrayList<List<Integer>>();//只能这样向上转型
//private List<List<Integer>> res = new ArrayList<ArrayList<Integer>>();//不能这样转型,这样是不对的
public List<List<Integer>> combine(int n, int k) {
if(n<=0 || n<k) return null;
List<Integer>item = new ArrayList<Integer>();
helper(n,k,1,item);
return res;
}
public void helper(int n,int k,int start,List<Integer> item) {
if(item.size()==k) {
res.add(new ArrayList<Integer>(item));
// res.add(item);//注意不能这样,因为添加进去的是item的引用,而后面item里的内容还在不断变化,导致res里的内容仍然是在变化的
return;
}
for(int i=start;i<=n;i++) {
item.add(i);
helper(n,k,i+1,item); //循环递归,很巧妙,认真理解
item.remove(item.size()-1);
}
}
}
具体例如:先item[1],然后item[1,2],添加到res,然后item移除末尾变成[1],再添加,变成[1,3],类似[1,4],[1],然后5不能加入,[1]->[],再从[2]开始循环下去
For example,
If n = 4 and k = 2, a solution is:
[ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]