DFS算法系列题 全排列II

本文介绍了如何使用DFS算法解决LeetCode中的全排列II问题,涉及重复数字的处理和剪枝技巧,通过创建特殊变量如check数组和path列表来确保不重复的全排列结果。
摘要由CSDN通过智能技术生成

DFS算法系列题 – 全排列II

DFS精选题- > 这次我们挑战的对象是:

全排列II

题目链接47. 全排列 II - 力扣(LeetCode)

这道题和我们之前做的全排列不同的点在于这道题的题目包含了重复的数字,要求我们返回不重复的全排列:

在这里插入图片描述

对此,我们需要引入一个算法策略来帮助我们解决重复数字的问题,那就是剪枝

剪枝:其实就是通过特定的条件将我们不需要的搜索路径去掉,从而提高我们的代码运行效率,这就类似于剪掉搜索树中无用的枝条

那么,上述这道题的需要满足的剪枝条件又是什么呢?

在于以下两点:

  • 同一个节点的所有的分支中,相同的数只能出现一次
  • 同一个元素只能出现一次

通过上述条件,我们可以画出对应的决策树来观察情况:

在这里插入图片描述

通过对上述决策树的分析,我们需要创建一些特殊的变量来满足我们的需求:

  • boolean[] check : 用来检测当前元素是否在之前层已经被使用过了
  • List<Integer> path : 用来记录路径
  • 我们通过int[] nums数组来存储元素,并且若当前层nums[i] == nums[i - 1] ,则可通过check[i - 1] == true来判断当前数字是否是当前层第一个使用的重复数字,若上一层使用了重复数字元素i - 1, 则check[i - 1] == true,此时当前层则未有对该重复数字的使用,在当前层就能使用重复数字i了
  • 到了新的一层会重新开始判断第一个重复的数字
  • 在进行上述重复数字判断前,我们需要将传递进来的数值列表进行排序,使得出现的重复数字前后挨在一起,方便使用i, i - 1判断

分析完后,接下来我们开始编写代码!

代码示例

class Solution {
    
    List<List<Integer>> ret;
    boolean[] check;
    
    public List<List<Integer>> permuteUnique(int[] nums) {
        ret = new ArrayList<>();
        check = new boolean[nums.length];
        Arrays.sort(nums); // 这里记得将数组按顺序排列
        dfs(nums, new ArrayList<>());
        return ret;
    }

    public void dfs(int[] nums, List<Integer> path) {

        if (path.size() == nums.length) {
            ret.add(new ArrayList<>(path));
            return;
        }

        for (int i = 0;i < nums.length;i++) {
            if (!check[i] && (i == 0 || nums[i] != nums[i - 1] || check[i - 1] == true)) {
             // 这里有个隐藏的条件,当nums[i] != nums[i-1] 时,由于是或判断,则能进行到check[i - 1] == true 判断则代表着num[i] == nums[i - 1]了
                path.add(nums[i]);
                check[i] = true;
                dfs(nums, path);
                path.remove(path.size() - 1);
                check[i] = false;
            }
        }
    }
}

在这里插入图片描述

这样这道题就解决了!总的来说这道题需要通过剪枝来找到解决重复问题的条件,并根据条件画出决策树进而编写dfs函数体!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值