全排列Ⅱ(中等难度,加入剪枝操作)

简介: 全排列Ⅱ(中等难度,加入剪枝操作)

目录

题目概述(中等难度)

思路与代码

思路展现

代码示例

题目概述(中等难度)

2.png


题目链接:

点我进入leetcode


思路与代码

思路展现

这道题目就是经典的回溯+DFS(深度优先搜索遍历),在这里我就不再给出我关于回溯的讲解了,leetcode的大佬已经帮我们总结到位了,只需要跟着他的题解走即可,在这里宣传以下weiwei大佬是一位非常厉害的大佬,除了他自己写的题解意外,也开设了自己的github网站帮助大家学习算法,在这里我都会将其网站贴到下面:

全排列Ⅱweiwei大佬题解链接

weiwei大佬github链接


这道题目是全排列题目的再进一步延申,只不过这道题目加入了两个条件,第一个就是这个序列中的元素有重复的,第二个就是需要按照任意顺序返回不重复的,在之前的全排列题目中我们的序列没有重复元素,所以最终我们返回的全排列就是没有重复元素的,而这次我们序列是有重复元素的,那么最终我们返回的全排列就肯定有重复元素,所以此时就需要用到剪枝,什么是剪枝以及如何用大家直接看weiwei大佬的题解就行啦,链接我已经放到了上面.


其实这段代码针对于之前的全排列其实就只多了几行代码,如下所示:

第一处:

首先要对我们的数组进行排序,因为数组有序是剪枝的前提

Arrays.sort(nums);

第二处:


if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
    continue;
}

我们来解释下为什么要加上面的代码

1:首先一个比较容易想到的办法是在结果集中去重。但是问题来了,这些结果集的元素是一个又一个列表,对列表去重不像用哈希表对基本元素去重那样容易。


如果要比较两个列表是否一样,一个容易想到的办法是对列表分别排序,然后逐个比对。既然要排序,我们就可以 在搜索之前就对候选数组排序,一旦发现某个分支搜索下去可能搜索到重复的元素就停止搜索,这样结果集中不会包含重复列表,所以此时我们用到了剪枝.

2:

为什么要加上nums[i] == nums[i - 1]?

例如对于【1,1’,2】这个数组,如果我们加上这个条件的话,相当于1’这个会产生与之前1相同的全排列结果的数字就不会再进行判断,直接跳到2去

但此时同学们思考一个问题,光加上这个条件够吗?

答:当然不够,原因如下

假设只判断这两个是否相等,很容易将我们本来符合条件的全排列删掉,例如假设如果是【1,1,2】这种组合,最终输出的结果是不存在全排列,因为前后只要重复就全部被剪掉了,所以说我们最终需要加上额外的判断条件

2.png

放到我们OJ的测试用例里面我们会发现有如下测试用例不通过:

2.png


此时为什么会有上面的问题出现,这是因为我们在判断具有重复元素的时候,并没有判断这两个重复的这个元素到底是在同一路径还是同一层,如果是同一路径是不能被剪枝的,而在同一层是可以被剪枝的,而这时我们判断两个重复的元素是在同一条路径还是在同层路径的标准是nums[i - 1] == false来进行判断的,假如此时nums[i - 1] = false的话,就说明我们这两个重复元素是在同层:如下所示:此类情况是必须进行剪枝的:原因是我们之前的1已经被选择过,并且状态从true置为了false,而此时这个新的1跟刚才1情况相同,所以就不需要再走一遍了,直接进行剪枝就好

2.png

而当nums[i - 1] = true的话,此类情况如下:

2.png

这种情况就说明是不能剪枝的.

总结:

2.png


代码示例

class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
      //len代表数组的长度
       int len = nums.length;
       //path是一个双端队列,使用Deque的原因是官方题解所给出的
       Deque<Integer> path = new LinkedList<>();
       //设置我们的res
       List<List<Integer>> res = new ArrayList<>();
       //设置我们所给定的nums数组中每个元素的初始状态为false
       boolean[] used = new boolean[len];
       if(len == 0) {
           return res;
       }
       //排序是剪枝的前提
       Arrays.sort(nums);
       dfs(path,used,nums,res,0,len);
       return res;
    }
    /*
    dfs方法参数介绍:
    path表示双端队列,用于存储我们所选择的路径上的数字
    boolean数组用于表示数字的选择与被选择,被选择为true,没有为false
    res用于存储最后的返回结果
    我们递归结束的条件与我们nums数组的长度len以及二叉树深度depth有很大的关系
    */
    public void dfs(Deque<Integer> path , boolean[] used , int[] nums , List<List<Integer>> res , int depth , int len) {
       if(depth == len) {
           //注意这里的写法其实是一个简便写法,就是直接实例化一个list集合然后将双端队列参数直接传入进去
           res.add(new ArrayList<>(path));
           //声明我们的递归终止条件
           return;
       }
       //!used[i]就表示此时假设这个数字还没有被选中,它的反就一定为true,然后才能进入到下面的语句
           for(int i = 0 ; i < len ; i++) { 
               if(!used[i]) {
               // 剪枝条件:i > 0 是为了保证 nums[i - 1] 有意义
               // 写 !used[i - 1] 是因为 nums[i - 1] 在深度优先遍历的过程中刚刚被撤销选择
               if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                   continue;
               }
               //选中后将数字加入到path中
               path.addLast(nums[i]);
               //选中后将状态置为true
               used[i] = true;
               //上面我们选择元素完毕后就开始我们的递归
               dfs(path  ,used , nums , res , depth + 1 , len);
               //进行完递归操作后接下来就需要我们进行撤回操作
               //1:撤回操作的第一步是将状态置为false
               used[i] = false;
               //2:撤回操作的第二步是将数字从path中移除
               path.removeLast();
           }
       }
    }
}

2.png

相关文章
|
Shell Linux 开发工具
Git版本控制工具详解(一)
Git版本控制工具详解
427 0
Git版本控制工具详解(一)
|
5天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
2705 9
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
13天前
|
人工智能 开发工具 iOS开发
Claude Code 新手完全上手指南:安装、国产模型配置与常用命令全解
Claude Code 是一款运行在终端环境中的 AI 编程助手,能够直接在命令行中完成代码生成、项目分析、文件修改、命令执行、Git 管理等开发全流程工作。它最大的特点是**任务驱动、终端原生、轻量高效、多模型兼容**,无需图形界面、不依赖 IDE 插件,能够深度融入开发者日常工作流。
3452 12
|
16天前
|
Shell API 开发工具
Claude Code 快速上手指南(新手友好版)
AI编程工具卷疯啦!Claude Code凭借任务驱动+终端原生的特性,成了开发者的效率搭子。本文从安装、登录、切换国产模型到常用命令,手把手带新手快速上手,全程避坑,30分钟独立用起来。
3530 25
|
9天前
|
人工智能 Linux BI
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
JeecgBoot AI专题研究 一键脚本:Claude Code + JeecgBoot Skills + DeepSeek 全平台接入 一行命令装好 Claude Code + JeecgBoot Skills + DeepSeek 接入,无需翻墙使用 Claude Code,支持 Wind
2667 6
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
|
7天前
|
人工智能 自然语言处理 供应链
|
7天前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全+三种模式+记忆体系+实战工作流完整手册
Claude Code 是当前最流行的终端级 AI 编程助手,能够直接在命令行中完成代码生成、项目理解、文件修改、命令执行、错误修复等全流程开发工作。它不依赖图形界面、不占用额外资源,却能深度理解项目结构,自动生成规范代码,大幅提升研发效率。
1227 3