本题对我理解recursive 和 backtracking 非常有帮助! 基本和N-Queen Problem 很相似的!
public static List<List<Integer>> combine(int n, int k) {
// write your code here
List<List<Integer>> result = new ArrayList<List<Integer>>();
List<Integer> list = new ArrayList<Integer>();
if (n == 0 || k == 0) {
return result;
}
helper(result, list, n, k);
System.out.println(result);
return result;
}
public static void helper(List<List<Integer>> result, List<Integer> list,
int n, int k) {
if (list.size() == k) { 递归的基本条件,也是终止条件。
result.add(new ArrayList(list));
return;
}
for (int i = 1; i <= n; i++) {
if (list.contains(i)) { 选择不重复的数字放进list
continue;
}
list.add(i);
System.out.println(list);
helper(result, list, n, k); 递归函数,这里要看递归的层数有多少。
list.remove(list.size() - 1); 递归结束后,会调用remove 函数,递归了多少层就会向上多少层。
System.out.println(list);
}
}
其实一开始不太明白,为什么要用for loop + 递归的模式。其实这个是非常经典的模板。回溯的方法有两个,一个是递归一个是非递归。这里用了递归的方式。
例如函数到了 helper(reslt,list,n,k) 进行递归,就会不断引用函数之前的值。我们在这里可以算出递归的层数:
例如 从1开始,到1,2,3,4 这里就会递归了三层,所以当list.remove(result, list, n, k ) 调用的时候,也要进行三次 恢复到原来的最上面的状态。 所以这里 remove 函数就是删除三次 变成 [1],因为for 也调用了三次,所以此时[1,2,3,4] 的位置也会第三个位置,3. 所以,这时候就会变成 [1,3] 然后进行下一次的递归。
其中list.remove的动作就是回溯的过程。所以这个模板非常重要,可以解很多相关的subsetting 的题目。