LintCode:Permutations

本题对我理解recursive 和 backtracking 非常有帮助! 基本和N-Queen Problem 很相似的!

public static List> combine(int n, int k) {
// write your code here
List> result = new ArrayList>();
List list = new ArrayList();
if (n == 0 || k == 0) {
return result;
}

    helper(result, list, n, k);
    System.out.println(result);
    return result;

}

public static void helper(List> result, List 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 的题目。

你可能感兴趣的:(LintCode:Permutations)