回溯(排列)

119 阅读1分钟

全排列

题目:46

  • 排列,讲究一个顺序的不同。相同的几个数,顺序不同还是不一样的排列
  • 所以这里和此前的找不同组合不同,不需要startIndex来去重
  • 这里就是只能用到used[i]了,只要保证当前正在选择的数不再被用就行了......吧
  • 结束条件:单个集合长度和数组长度一样,毕竟是全排列啦。这里仍然可以把它当作二叉树,到达叶子节点即可。
  • 因为排列问题,每次都要从头开始搜索,例如元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次1。

而used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次

  • 这里的used[]就是索引上的是否被使用,如果这个path(单个答案集合)里已经用过了这个数,就跳过
        for (int i = 0; i < nums.length; i++){
            if (used[i]){
                continue;
            }
  • 排列问题与之前的不同:
  • 每层都是从0开始搜索而不是startIndex
  • 需要used数组记录path里都放了哪些元素了
  • 或许,把used数组当作全局变量,是看这个树在深度上有没有被重复用的数字,就是这个全排列。在一个方法里,就是代表当前层(例如上一题那个递增子序列

全排列II

题目:47

  • 引入重复数字,找没有重复的排序组合
  • 那么就是在排列问题的基础上引入常规的去重操作,先给数组排序再用used[i]的那种,毕竟全排序里没有startIndex
            if (i > 0 && !used[i - 1] && nums[i - 1] == nums[i]) {
                continue;
            }
  • 如果要对树层中前一位去重,就用used[i - 1] == false,毕竟,额,都到了nums[i]了,说明nums[i-1]应该已经被回溯过/用过了,已经是false了......吧?
  • 如果要对树枝前一位去重用used[i - 1] == true 不过推荐用对数层前一位去重
  • 同时不要忘记,只有发现这个元素没在path里用过的时候,才能进行递归到下一层然后回溯哦
            if (used[i] == false) {
                path.add(nums[i]);
                used[i] = true;
                backTracking(nums,used);
                path.remove(path.size() - 1);
                used[i] = false;
            }

一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果