leetcode47. 全排列 II 回溯剪枝的细节问题

news2024/12/27 17:47:56

题目描述:

 1、思路

        作为回溯算法的经典问题,常用的方法是,每次dfs前先判断是否达到临界条件,满足条件则加入结果集并return。通过循环和dfs来构建树,查找出全部满足条件的集合。
        例如本题,如1,2,3的排列组合,可以先选1,然后选2or3,选了2然后只可以选3,依此类推。


        实际上,回溯的dfs就是在纵向地深度遍历,for循环就是在横向地遍历。

剪枝:

        首先,每次选了1以后,下一次肯定不能选1;如果已经选了1,2,那么下一次就不能选1和2,因此我们需要构建一个used数组来记录每个数字是否被选择,在每次循环开始前判断used是否被使用,从而实现剪枝。

        但这样只能应付上图的无重复情况,对于下图这种情况,我们发现不仅每次深度搜索需要去重,横向的循环也需要:例如,选第一个1、第二个1 、2 第二个1 、第一个1、2  都是[1,1,2],是重复的组合,这也需要排除。

         因此,我一开始就想,在每次循环内的开始,再加一个判断,只要当前元素和上一个元素不同(前提是有序数组),不就ok了?即,当循环到第二个1的时候,判断上一个是不是1,如果是,则return即可!见下面代码:

代码如下:

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        Deque<Integer> path = new ArrayDeque<>();
        Arrays.sort(nums);
        int len = nums.length;
        boolean[] used = new boolean[len];//used false
        backTrace(nums,path,used,len);
        return res;
    }
    public void backTrace(int[] nums, Deque<Integer> path, boolean[] used,int len){
        if(path.size() == len){
            res.add(new ArrayList<>(path));
            return;
        }
        
        for(int i = 0; i < len; i++){
            if(used[i]){//保证深度搜索不会放置自己(不重复位置)
                continue;
            }

            //这一步,出现错误:
            if(i > 0 && nums[i] == nums[i-1])continue;//保证水平不重复元素
               
            used[i] = true;
            path.add(nums[i]);
            backTrace(nums,path,used,len);
            used[i] = false;
            path.removeLast();
        }
    }
}

        哈哈,测试发现输出结果是个[ ],空集合。明明纵向的去重了,横向也去重了,是哪里出错了呢?一步一步思考发现了问题如下。

 2.修正错误:

//修正
if(i > 0 && nums[i] == nums[i-1])continue;

        对于这里的水平去重,的确,每一轮循环到i的时候都可以判断是否和i-1元素相同,来实现不会选择值一样的元素,能够完成图中橙色的叉叉的剪枝。
        但是它在每一轮循环里,同时会剪掉纵向遍历过程的相同数字! 例如下图的绿色叉叉:


        因为,在绿色叉叉这一层,[1,1,2]这样的组合,不能够说 第二个1第 一个1相同就continue,那样的话这种正确答案就被排除了!
        关键:也就是说,第一个1仍在被使用(true)的时候,是可以加入别的相同的1的。与之相反的,当第一个1被置为false后,这样的等值判断才有效。
        
因此可以这样修改代码,见注释:

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> permuteUnique(int[] nums) {
        Deque<Integer> path = new ArrayDeque<>();
        Arrays.sort(nums);
        int len = nums.length;
        boolean[] used = new boolean[len];//used false
        backTrace(nums,path,used,len);
        return res;
    }
    public void backTrace(int[] nums, Deque<Integer> path, boolean[] used,int len){
        if(path.size() == len){
            res.add(new ArrayList<>(path));
            return;
        }
        
        for(int i = 0; i < len; i++){
            if(used[i]){//保证深度搜索不会放置自己(不重复位置)
                continue;
            }
//只有在和上一个元素相等,并且上一个元素此时并没有被使用,
//说明已经执行了used[i] = false;说明已经用过,这才return。
//否则就是1,1,2的情况,第二个1是可以加入结果的。
            if(i > 0 && nums[i] == nums[i-1] && !used[i-1])continue;//保证水平,不重复元素
            used[i] = true;
            path.add(nums[i]);
            backTrace(nums,path,used,len);
            used[i] = false;
            path.removeLast();
        }
    }
}

        ok,答案正确。
        这个题目涵盖了纵向和横向的两种剪枝,并且需要注意横向的剪枝判断对纵向剪枝的影响,需要仔细思考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/740924.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

dp动态规划详解下

dp动态规划详解上&#xff1a;https://blog.csdn.net/weixin_73936404/article/details/131527247?spm1001.2014.3001.5501 目录 dp动态规划详解上&#xff1a;https://blog.csdn.net/weixin_73936404/article/details/131527247?spm1001.2014.3001.5501 【案例1】 【题目描…

强度(极限强度、屈服强度)、韧性材料与脆性材料(韧性材料与脆性材料的强度、为什么脆性材料在压缩时比在拉伸时更坚固?)、材料的延展性、韧性、弹性

1.强度 强度&#xff08;Strength&#xff09;是材料可以承受的应力的量度&#xff0c;通常使用极限强度&#xff08;Ultimate strength&#xff09;和屈服强度&#xff08;Yield strength&#xff09;来定义材料的强度-极限。 材料的极限抗拉强度定义为在拉伸试验过程中达到的…

windows 编译libyuv

一、libyuv下载 git clone https://chromium.googlesource.com/external/libyuv 二、libjpeg-turbo下 git clone https://github.com/libjpeg-turbo/libjpeg-turbo.git 三、编译可以参考 BUILDING.md 需要环境&#xff1a; VS2019 CMake YASM 启动vs工具 编译&#xff1…

js模块化开发

◼ 到底什么是模块化、模块化开发呢&#xff1f;  事实上模块化开发最终的目的是将程序划分成一个个小的结构&#xff1b;  这个结构中编写属于自己的逻辑代码&#xff0c;有自己的作用域&#xff0c;定义变量名词时不会影响到其他的结构&#xff1b;  这个结构可以将自己…

SAP S4 Hana 下面ACDOCA 凭证行字段增强创建过程

网上找到这个类下面是可以新增增强的 现在需要在如下位置建立四代增强点 保存以后会出现下面的增强项 保存激活后&#xff0c;完成在源程序中增加了一个4代显式增强点.上面步骤只是在程序中建立了一个增强点&#xff0c;并没有执行什么动作&#xff0c;就相当于建立一个容器。如…

Python将Excel数字对应列的字母写成字典(json)

在日常的办公中&#xff0c;我们经常需要利用python去读写Excel类型的文件&#xff0c;有时候我们需要将每个数字代表的列的字母表现出来&#xff0c;那么我们可以利用Python实现&#xff0c;而且今天的代码可以根据自己的需求去任意的改变你想规定的长度 如,或者更长 a {1:…

1分钟搭建VPN服务器

1分钟搭建一个VPN服务器 VPN技术在保障网络通信安全和隐私上发挥着重要作用。IPsec VPN是其中一种常用的VPN模式。本文将介绍如何通过使用Docker来快速搭建IPsec VPN Server。 什么是IPsec VPN&#xff1f; IPsec即Internet Protocol Security&#xff0c;是一种用于保护互联…

「2024」预备研究生mem- 形式逻辑强化:逻辑的特殊文字表述方式(重点记忆)

一、形式逻辑强化&#xff1a;逻辑的特殊文字表述方式 二、课后题

关于torch.load报出找不到模型的错误,但路径明明正确

后来发现是因为使用 torch.save(model,save.pt) 会保存整个文件时会默认保存训练py文件的父目录&#xff0c;用torch.load导入文件时搜索路径必须有此父路径&#xff0c;否则将会提示no model named model这样的错误 解决办法是使用sys.path.apend把该父目录加入搜索路径中 …

Java开发 - 探寻Spring的秘密

前言 Spring是企业级J2EE一站式解决方案&#xff0c;提供了整个项目的表现层、业务层、持久层&#xff0c;而且&#xff0c;它的生态特别完善&#xff0c;可以和其他框架无缝对接&#xff0c;现在做Java的哪个项目里没有Spring的说出不去都不信。但往往我们开发者只重视项目是…

重定向:电商行业打败对手的杀手锏

重定向是一种在线营销策略&#xff0c;针对对产品或服务表示兴趣的潜在客户。可以追踪那些访问过您的网站、但未进行过消费的用户&#xff0c;再次向他们展示相关产品&#xff0c;激起消费欲。再营销则是可以追踪那些将商品加入网页购物车&#xff0c;但最后没有购买的用户&…

物流RFID设备一般在哪些场景应用?

随着现代物流行业的快速发展&#xff0c;传统条码技术信息量少&#xff0c;易脏污损毁&#xff0c;耐用性不高等问题很难满足物流企业多样化的需求&#xff0c;物流RFID设备的应用也越来越广泛。下面我们就跟大家一起来分析一下&#xff0c;物流RFID设备可以在哪些场景中应用。…

计算机体系结构基础知识介绍之动态调度(三)

首先回顾一下tomasulo算法&#xff0c; Tomasulo算法的第一个优点是分布式的冒险检测逻辑&#xff0c;这是通过使用预留站和公共数据总线实现的。预留站是一种存储指令和操作数的缓冲区&#xff0c;每个功能单元都有自己的预留站。公共数据总线是一种广播结果的方式&#xff0…

SpringBoot07:Thymeleaf模板引擎

目录 一、Thymeleaf 1、模板引擎 2、引入Thymeleaf 3、Thymeleaf分析 二、测试 1、编写一个TestController 2、编写一个测试页面welcome.html放在templates目录下 3、启动项目请求测试 三、Thymeleaf语法学习 1、修改测试请求&#xff0c;增加数据传输 2、要使用thy…

zabbix服务部署

文章目录 zabbix1 zabbix简介1.1 组成部件1.2 监控原理1.3 Zabbix 6.0新特性1.4 Zabbix6.0功能组件1.4.1 Zabbix Server1.4.2 数据库1.4.3 Web界面1.4.4 Zabbix Agent1.4.5 Zabbix Proxy1.4.6 Java Gateway 2 部署zabbix服务端2.1 部署Nginx2.2 安装PHP2.3 修改Nginx配置2.4 修…

Docker安装ElasticSearch7.14.0 docker安装elasticsearch7.14.0完整详细教程

Docker安装ElasticSearch7.14 docker安装elasticsearch7.14完整详细教程 Docker 上安装 ElasticSearch 7.14.0 的步骤&#xff1a;选择要安装的ElasticSearch 版本1、拉取 ElasticSearch 镜像2、创建并运行容器关闭容器启动容器重启容器 3、elasticsearch常用端口以及作用4、测…

耳夹式骨传导耳机测评!2023年最全耳夹骨传导耳机盘点

现在市面上的骨传导耳机品牌层出不穷&#xff0c;骨传导耳机好不好用&#xff0c;主要还是看耳机的品牌背景以及独家的音质技术调配&#xff0c;较大的骨传导耳机品牌在购买时售后以及使用体验上都具有一定的保障&#xff0c;下面就分享一些值得入手的骨传导耳机给大家吧~ 第一…

安装.net framework3.5 无法打开运行空间池,服务器管理器winRM插件可能已经损坏

解决方案&#xff1a; 1.以管理员权限打开命令提示符&#xff0c;然后运行如下命令&#xff1a; "reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f" 2.然后运行"winrm quickco…

玩转 TypeScript 中【class类】的定义与使用方法解读。

目录 类的概念类的继承 &#xff1a;类的存取器&#xff1a;类的静态方法与静态属性&#xff1a;类的修饰符&#xff1a;参数属性&#xff1a;抽象类&#xff1a;类的类型: 类的概念 类是用于创建对象的模板。他们用代码封装数据以处理该数据。JavaScript 中的类建立在原型上&a…

java.lang.NoSuchMethodError异常原因及解决办法

java.lang.NoSuchMethodError异常原因及解决办法 第一种简单的情况就是本类中需要调用的方法名称错误&#xff0c;这种情况就需要去检查方法名称是否正确&#xff0c;避免调用的方法和本类中的有相同的名称。 第二种情况就是jar包的问题 可能是jar包没有导入进来或者jar包导入…