力扣:包含重复元素的全排列问题

给定一个可包含重复数字的序列,返回所有不重复的全排列

这题与上题的全排列问题类似,问题在于如何将重复序列排除在外。
这里就需要剪枝思想,即去掉多余的子树。
我们先看图,令nums=[1,1,2] ![](https://img2020.cnblogs.com/blog/1809280/202004/1809280-20200430115337390-1498940799.png) 图中可以看出,[1]节点与[1]节点一致,当[1`]节点选择子节点时与[1]节点选择时一致,故应该去除。类推。
再看如何判断剪枝:
nums[0]=1,nums[1]=1.我们需要将nums[i-1]与nums[i]进行数值判断。同时在nums[i]为父节点进行遍历时,判断nums[i-1]是否已被调用。同时注意边界i>0;
代码在全排列问题上添加一个剪枝语句。

public List<List<Integer>> permute(int[] nums) {
        int numsLength = nums.length; // numsLength为nums长度
        List<List<Integer>> res = new ArrayList<>(); // 返回值
        Array.sort(nums); // 排序是剪枝的前提
        Deque<Integer> path = new ArrayDeque<>(); // path类型为Stack类型,系统推荐使用Deque。
                                                    // path用来存放每一次遍历结果
        boolean[] tOf = new boolean[numsLength]; // boolean数组对应nums中数字是否被遍历
        dfs(nums,numsLength,0,path,tOf,res);
        return res;
    }

    private void dfs(int[] nums, int numsLength, int depth, Deque<Integer> path, boolean[] tOf, List<List<Integer>> res) {
        // 遍历结束条件
        if (numsLength == depth) {
            res.add(new ArrayList<>(path));
            return;
        }

        // for循环遍历
        for (int i = 0; i < numsLength; i++) {
            // 判断nums中数字是否被遍历到
            if (tOf[i]) {
                continue;
            }
            // 进行剪枝判断
            if (i>0 && nums[i] == nums[i -1] && !tOf[i-1]) {
                continue;
            }
            // 若未被遍历
            path.addLast(nums[i]); // 将遍历到的nums[i]放入path尾部
            tOf[i] = true; // 将对应tof置为true,表示已遍历
            dfs(nums,numsLength,depth+1,path,tOf,res); // 继续向下搜索
            path.removeLast(); // 假设[1][2][3]回溯,返回上一层[1][2]。但是如何继续返回[1]节点呢
                                // 这时候tof[1]为true,代表nums[1]已被遍历,继续回撤。
            tOf[i] = false;
        }
    }

有错误或有其他想法的朋友们欢迎评论。

posted @ 2020-04-30 12:50  梧桐更兼细雨_到黄昏  Views(411)  Comments(0Edit  收藏  举报