回溯题中借助哈希法来巧妙去重的操作

今天总结一下回溯法以来做过的这些题,我又发现一个困扰了我的问题,就是在491. 非递减子序列、46. 全排列、47. 全排列 II中都有涉及到用哈希法,去记录曾经用过的元素,下面来总结一下吧。
首先得知道,为什么会用到哈希法?

为什么会用到哈希法?

在491. 非递减子序列问题中,是因为集合中有相同的元素,而结果又不能出现相同的组合,如本题的示例1 [4,6,7,7]中,当4与倒数第二个7组合时,一个答案为[4,7],而下一个,与倒数第一个7则不能再组合了,即不能出现两个[4,7],借代码随想录里的图来理解,就是同一层不能重复使用相同的数字,如图:Alt
而这时,就可以利用一个哈希表,来保存每一层使用过哪些元素,注意这里的每一层这个要求,结合下面的代码理解一下:

非递减子序列代码:

public void backtracking(int[] nums, int startIndex) {if(temp.size() >= 2) {result.add(new ArrayList<>(temp));}Set<Integer> set = new HashSet<>(); // 在每一层递归中,设置一个Set哈希表,记录这一层使用过哪些元素for(int i = startIndex; i < nums.length; i++) {// 解决递增以及重复的问题if(!temp.isEmpty() && (nums[i] < temp.get(temp.size() - 1)) || set.contains(nums[i])) {continue;}temp.add(nums[i]);set.add(nums[i]);backtracking(nums, i + 1);temp.remove(temp.size() - 1);}}

而在全排列问题中,则不是记录每一层,而是记录某条树枝上(即整个递归中)哪些元素使用过,例如46. 全排列中的示例1的数据[1,2,3],由于排列的特点,for循环每次都从0开始,但是要保证不能重复选某个元素,所以要用哈希表来记录,哪些数字用了,哪些没有,下面是代码,重在理解“某条树枝上(即整个递归中)哪些元素使用过”。

全排列代码:

class Solution {List<Integer> temp = new ArrayList<>();List<List<Integer>> result = new ArrayList<>();boolean[] table = new boolean[21];  // 哈希表,记录整个递归中使用过的元素public List<List<Integer>> permute(int[] nums) {backtracking(nums);return result;}public void backtracking(int[] nums) {if(temp.size() == nums.length) {result.add(new ArrayList<>(temp));return;}for(int i = 0; i < nums.length; i++) {// 去重操作if(!temp.isEmpty() && table[nums[i] + 10]) {continue;}temp.add(nums[i]);table[nums[i] + 10] = true;    // 设置哈希表,使用过的元素记录backtracking(nums);temp.remove(temp.size() - 1);  // 回溯table[nums[i] + 10] = false;   // 回溯之后,使用过的记录也清空}}
}

而这道题的升级版:47. 全排列 II,由于出现了重复元素,为了还能全排列,设计哈希表时,就不是记录值而是记录使用过的元素的位置了,因为排列时,使用的数字位置不同,排列也是不同的,所以对于全排列 II,哈希表记录的是整个递归中,使用的是哪个位置的元素,下面是代码:

全排列 II代码:

class Solution {List<Integer> temp = new ArrayList<>();List<List<Integer>> result = new ArrayList<>();public List<List<Integer>> permuteUnique(int[] nums) {Arrays.sort(nums);// 排序是为了后面的组间去重boolean[] used = new boolean[nums.length]; 	// 其实这个放在全局变量也行backtracking(nums, used);return result;}public void backtracking(int[] nums, boolean[] used) {if(temp.size() == nums.length) {result.add(new ArrayList<>(temp));return;}for(int i = 0; i < nums.length; i++) {if(used[i]) {		// 判断当前这个位置的元素是否在前面的递归中使用过,如果使用过,则排列下面的元素 continue;}temp.add(nums[i]);used[i] = true;backtracking(nums, used);temp.remove(temp.size() - 1);used[i] = false;	// 回溯不要忘了把丢弃的元素也设置为“未使用”while(i + 1 < nums.length && nums[i +1] == nums[i]) {// 去重操作i++;}}}
}

总结

可以看出来,其实用上哈希法,就是两种情况,要么是要判断同一层是否使用过,要么是要判断整个递归中是否使用过,对应就是哈希表定义的地方不同,要判断同一层是否使用过,哈希表定义在递归函数里;要判断整个递归中是否使用过,哈希表定义在全局变量中或者定义在递归函数之外

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

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

相关文章

wordpress外贸成品网站模板

首页大图slider轮播&#xff0c;橙色风格的wordpress外贸网站模板 https://www.zhanyes.com/waimao/6250.html 蓝色经典风格的wordpress外贸建站模板 https://www.zhanyes.com/waimao/6263.html

RapidMiner数据挖掘2 —— 初识RapidMiner

本节由一系列练习与问题组成&#xff0c;这些练习与问题有助于理解多个基本概念。它侧重于各种特定步骤&#xff0c;以进行直接的探索性数据分析。因此&#xff0c;其主要目标是测试一些检查初步数据特征的方法。大多数练习都是关于图表技术&#xff0c;通常用于数据挖掘。 为此…

【复现】cellinx摄像设备 未授权漏洞_50

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 cellinx是一家韩国的摄像设备 二 .漏洞影响 通过未授权访问可以创建用户进入后台&#xff0c;可能造成系统功能破坏。 三.漏洞复…

多线程面试题汇总

多线程面试题汇总 一、多线程1、线程的生命周期2、线程的创建&#xff08;函数创建&#xff09;3、线程的创建&#xff08;使用类&#xff09;4、守护线程 二、全局解释器锁1、使用单线程实现累加到5000000002、使用多线程实现累加到5000000003、总结 三、线程安全1、多线程之数…

SQL的1999语法

目录 交叉连接 实现交叉连接 自然连接 实现自然连接&#xff08;实际上就是内连接&#xff09; ON和USING 使用自然连接时要求两张表的字段名称相同&#xff0c;但是如果不相同或者两张表中有两组字段是重名,这时就要利用 ON 子句指定关联条件&#xff0c;利用 USING 子句…

【Android】使用Apktool反编译Apk文件

文章目录 1. 下载Apktool1.1 Apktool官网下载1.2 百度网盘下载 2. 安装Apktool3. 使用Apktool3.1 配置Java环境3.2 准备Apk文件3.3 反编译Apk文件3.3.1 解包Apk文件3.3.2 修改Apk文件3.3.3 打包Apk文件3.3.4 签名Apk文件 1. 下载Apktool 要使用Apktool&#xff0c;需要准备好 …

OpenSource - 一站式自动化运维及自动化部署平台

文章目录 orion-ops 是什么重构特性快速开始技术栈功能预览添砖加瓦License orion-ops 是什么 orion-ops 一站式自动化运维及自动化部署平台, 使用多环境的概念, 提供了机器管理、机器监控报警、Web终端、WebSftp、机器批量执行、机器批量上传、在线查看日志、定时调度任务、应…

2.14:二维数组、非函数实现strcat、strcmp、strcpy、strlen

1.编程实现二维数组的杨辉三角 程序代码&#xff1a; 1 #include<stdio.h>2 #include<string.h>3 #include<stdlib.h>4 int main(int argc, const char *argv[])5 {6 int n;7 printf("please enter n:");8 scanf("%d",&…

C++文件操作->文本文件(->写文件、读文件)、二进制文件(->写文件、读文件)

#include<iostream> using namespace std; #include <fstream>//头文件包含 //文本文件 写文件 void test01() { //1.包含头文件 fstream //2.创建流对象 ofstream ofs; //3.指定打开方式 ofs.open("test.txt", ios::out); //4.写…

蓝桥杯嵌入式学习记录——PWM输出

目录 一、PWM原理介绍 二、学习目的 三、cubeMX的配置 四、PWM输出代码 一、PWM原理介绍 PWM&#xff08;Pulse Width Modulation&#xff0c;脉宽调制&#xff09;是一种通过改变信号的脉冲宽度来控制电平的技术。它通过调整脉冲信号的占空比&#xff08;高电平时间与周期…

互联网加竞赛 基于计算机视觉的身份证识别系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器视觉的身份证识别系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-sen…

【STM32 CubeMX】I2C中断方式与DMA方式

文章目录 前言一、I2C中断方式1.1 CubeMX配置I2C中断1.2 I2C中断函数使用Master模式Mem模式 1.3 DMA方式发送和接收CubeMX配置IIC DMA方式Master模式Mem模式 总结 前言 在STM32 CubeMX环境中&#xff0c;I2C&#xff08;Inter-Integrated Circuit&#xff09;通信协议的实现可…

基于非线性系统的Lipschitz观测器simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1非线性系统及观测器概述 4.2 Lipschitz观测器原理 5.完整工程文件 1.课题概述 基于非线性系统的Lipschitz观测器simulink建模与仿真&#xff0c;该系统设计了一个观测器&#xff0c;称为Lipschitz观…

Capacity Maximization for Movable Antenna Enabled MIMO Communication

文章目录 II. SYSTEM MODEL AND PROBLEM FORMULATIONC. Problem Formulation III. PROPOSED ALGORITHMA. Alternating OptimizationB. Solution for Problem (P2-m) APPENDIX II. SYSTEM MODEL AND PROBLEM FORMULATION C. Problem Formulation 为了揭示支持 MA 的MIMO通信的…

【LeetCode: 103. 二叉树的锯齿形层序遍历 + BFS】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

嵌入式培训机构四个月实训课程笔记(完整版)-Linux ARM驱动编程第三天-ARM Linux ADC和触摸屏开发 (物联技术666)

链接&#xff1a;https://pan.baidu.com/s/1V0E9IHSoLbpiWJsncmFgdA?pwd1688 提取码&#xff1a;1688 教学内容&#xff1a; 1、ADC S3C2440的A/D转换器包含一个8通道的模拟输入转换器&#xff0c;可以将模拟输入信号转换成10位数字编码。 在A/D转换时钟频率为2.5MHz时&…

第三十回 张都监血溅鸳鸯楼 武行者夜走蜈蚣岭-python可接受任意数量参数的函数

武松回到孟州城&#xff0c;来到张都监后花园墙外&#xff0c;这是一个马院&#xff0c;问清楚后槽张团练他们三人还在鸳鸯楼吃酒&#xff0c;直接一刀杀了。武松从后门这里爬过墙&#xff0c;来到了厨房&#xff0c;将两个还在服侍的丫环杀了。 武松认得路&#xff0c;蹑手蹑…

Java Web 中forward 和 redirect 的区别

前言 在Java Web开发中&#xff0c;页面跳转是构建用户界面和实现业务逻辑的重要组成部分。Forward&#xff08;转发&#xff09;和Redirect&#xff08;重定向&#xff09;是两种常见的跳转方式&#xff0c;它们分别具有不同的特点和适用场景。正确地选择和使用这两种跳转方式…

高性能MySQL 阅读笔记

mysql由服务器端与存储引擎两部分组成&#xff0c;存储引擎部分的锁机制对服务器端是透明的。服务器端内置缓存机制&#xff0c;有解析器和优化器机制。不同的存储引擎对事务、并发等都用不同的处理。 ACID代表的特性&#xff1a;原子性、一致性、隔离性、持久性 共享锁与排他…

ChatGPT重大升级:能自动记住用户的习惯和喜好,用户有权决定是否共享数据给OpenAI

OpenAI刚刚宣布了ChatGPT的一项激动人心的更新&#xff01; OpenAI在ChatGPT中新加了记忆功能和用户控制选项&#xff0c;这意味着GPT能够在与用户的互动中记住之前的对话内容&#xff0c;并利用这些信息在后续的交谈中提供更加相关和定制化的回答。 这一功能目前正处于测试阶…