当前位置: 首页 > news >正文

【算法系列篇】递归、搜索和回溯(四)

在这里插入图片描述

文章目录

  • 前言
  • 什么是决策树
  • 1. 全排列
    • 1.1 题目要求
    • 1.2 做题思路
    • 1.3 代码实现
  • 2. 子集
    • 2.1 题目要求
    • 2.2 做题思路
    • 2.3 代码实现
  • 3. 找出所有子集的异或总和再求和
    • 3.1 题目要求
    • 3.2 做题思路
    • 3.3 代码实现
  • 4. 全排列II
    • 4.1 题目要求
    • 4.2 做题思路
    • 4.3 代码实现

前言

前面我们通过几个题目基本了解了解决递归类问题的基本思路和步骤,相信大家对于递归多多少少有了更加深入的了解。那么本篇文章我将为大家分享结合决策树来解决递归、搜索和回溯相关的问题。

什么是决策树

决策树是一种基本的分类与回归方法。在分类问题中,决策树通过构建一棵树形图来对数据进行分类。树的每个节点表示一个特征属性,每个分支代表一个特征属性上的判断条件,每个叶节点代表一个类别。在回归问题中,决策树可以预测一个实数值。

下面是一个简单的决策树:
在这里插入图片描述
知道了什么是决策树,下面我们将运用决策树来解决实际问题。

1. 全排列

https://leetcode.cn/problems/permutations/

1.1 题目要求

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]

示例 3:

输入:nums = [1]
输出:[[1]]

提示:

1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums 中的所有整数 互不相同
class Solution {public List<List<Integer>> permute(int[] nums) {}
}

1.2 做题思路

相信大家肯定做过跟排列相关的问题,就是三个人坐座位的问题。第一座位可以坐A、B、C 任何一个人,如果第一个座位坐的是 A 的话,那么第二个位子 A 就不能再坐了,第二个位子就只能在 B、C 之间选择了,如果 B 选择了第二个位子,那么第三个位置就只能 C 选择了。所以这个问题通过决策树来体现的话就是这样的:

在这里插入图片描述
但是上面的图我们会发现这几种情况会有重复的情况,那么我们如何筛选掉这些重复的情况呢?可以使用一个标记数组来记录已经选择过的元素,当下一次选择的时候就选择这个标记数组中没有被选择的剩下的元素的其中一个。这道题目跟上面的例子的思路是一样的,这里我就不为大家再画一个图了。

那么这道题使用代码的思想该如何解决呢?每次递归我们还是将数组中的所有元素都给列举出来,不过我们需要根据标记数组中元素的使用情况来选择是否可以选择这个元素,如果某个元素没有被选择,那么这次就选择这个元素,将这个元素标记为已使用,然后继续递归,当当前情况列举完成之后就需要恢复现场,当路径集合中记录的元素的个数和数组中的元素个数相同的时候,就说明一种情况已经列举完成,就可以将当前情况添加进ret集合中,返回。

1.3 代码实现

class Solution {List<Integer> path;List<List<Integer>> ret;boolean[] vis;public List<List<Integer>> permute(int[] nums) {//对全局变量进行初始化path = new ArrayList<>();ret = new ArrayList<>();vis = new boolean[nums.length];dfs(nums);return ret;}private void dfs(int[] nums) {//当path中元素的大小等于数组的大小,就说明一种情况已经列举完成,这事需要我们将当前path中的数据添加进ret中,并且返回if (path.size() == nums.length) {ret.add(new ArrayList<>(path));return;}for (int i = 0; i < nums.length; i++) {if (vis[i] == false) {path.add(nums[i]);//将当前元素标记为已使用vis[i] = true;//考虑该位置之后的其他元素的选择dfs(nums);//恢复现场path.remove(path.size() - 1);vis[i] = false;}}}
}

在这里插入图片描述

2. 子集

https://leetcode.cn/problems/subsets/

2.1 题目要求

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

1 <= nums.length <= 10
-10 <= nums[i] <= 10
nums 中的所有元素 互不相同
class Solution {public List<List<Integer>> subsets(int[] nums) {}
}

2.2 做题思路

前面全排列中是当路径集合中的元素个数和数组中的元素的个数相同的时候视为一种情况,这道题目就不一样了,这个是数组的子集,也就是说每一种情况的元素的个数可能是不一样的,所以我们路径集合每新添加一个元素就可以视为一种情况,就需要将路径中的元素添加进ret集合中,思路跟上一道题目是类似的,都是通过决策树递归来实现的,但是呢?仔细看题目可以发现,就是集合[1,2],[2,1]是一种情况,也就是说子集的选择跟顺序无关,那么我们又该如何避免出现重复的情况呢?

这其实也不难,想想如果是在数学中我们会怎样思考?如果当前位置我们选择了某个元素,那么后面的位置我们就从这个元素的后面元素中去选择。

在这里插入图片描述
所以通过代码体现的话,就是我们可以使用一个 pos 变量来记录当前位置选择的元素的下标,然后下一个位置选择元素递归的话,我们就从 pos 的下一个位置开始选择。

2.3 代码实现

class Solution {List<Integer> path;List<List<Integer>> ret;public List<List<Integer>> subsets(int[] nums) {path = new ArrayList<>();ret = new ArrayList<>();dfs(nums, 0)return ret;}private void dfs(int[] nums, int pos) {//进入这个函数就可以将path中的结果添加进ret中,这样就可以将空集的情况给考虑上ret.add(new ArrayList<>(path));//循环的话,就从pos位置开始遍历for (int i = pos; i < nums.length; i++) {path.add(nums[i]);dfs(nums, i + 1);path.remove(path.size() - 1);}}
}

在这里插入图片描述

3. 找出所有子集的异或总和再求和

https://leetcode.cn/problems/sum-of-all-subset-xor-totals/

3.1 题目要求

一个数组的 异或总和 定义为数组中所有元素按位 XOR 的结果;如果数组为 空 ,则异或总和为 0 。

例如,数组 [2,5,6] 的 异或总和 为 2 XOR 5 XOR 6 = 1 。
给你一个数组 nums ,请你求出 nums 中每个 子集 的 异或总和 ,计算并返回这些值相加之 和 。

注意:在本题中,元素 相同 的不同子集应 多次 计数。

数组 a 是数组 b 的一个 子集 的前提条件是:从 b 删除几个(也可能不删除)元素能够得到 a 。

示例 1:

输入:nums = [1,3]
输出:6
解释:[1,3] 共有 4 个子集:
- 空子集的异或总和是 0 。
- [1] 的异或总和为 1 。
- [3] 的异或总和为 3 。
- [1,3] 的异或总和为 1 XOR 3 = 2 。
0 + 1 + 3 + 2 = 6

示例 2:

输入:nums = [5,1,6]
输出:28
解释:[5,1,6] 共有 8 个子集:
- 空子集的异或总和是 0 。
- [5] 的异或总和为 5 。
- [1] 的异或总和为 1 。
- [6] 的异或总和为 6 。
- [5,1] 的异或总和为 5 XOR 1 = 4 。
- [5,6] 的异或总和为 5 XOR 6 = 3 。
- [1,6] 的异或总和为 1 XOR 6 = 7 。
- [5,1,6] 的异或总和为 5 XOR 1 XOR 6 = 2 。
0 + 5 + 1 + 6 + 4 + 3 + 7 + 2 = 28

示例 3:

输入:nums = [3,4,5,6,7,8]
输出:480
解释:每个子集的全部异或总和值之和为 480 。

提示:

1 <= nums.length <= 12
1 <= nums[i] <= 20
class Solution {public int subsetXORSum(int[] nums) {}
}

3.2 做题思路

这道题目跟上面的子集思路基本上没什么区别,之不过上面的子集是要求出所有子集的情况,而这道题目是求出所有子集异或之后的总和。因为思路基本跟上个题一样,所以我们直接来看代码。

3.3 代码实现

class Solution {int path;int ret;public int subsetXORSum(int[] nums) {dfs(nums, 0);return ret;}private void dfs(int[] nums, int pos) {//前面是将集合添加进ret中,这里我们是将每种情况加进ret中ret += path;for (int i = pos; i < nums.length; i++) {//这里我们不是将新加入的元素加入到path集合中,而是将新加入的元素和之前path元素的异或的结果异或path ^= nums[i];dfs(nums, i + 1);//恢复现场(两个相同的元素异或,结果为0)path ^= nums[i];}}
}

在这里插入图片描述

4. 全排列II

https://leetcode.cn/problems/permutations-ii/

4.1 题目要求

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]

示例 2:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

提示:

1 <= nums.length <= 8
-10 <= nums[i] <= 10
class Solution {public List<List<Integer>> permuteUnique(int[] nums) {}
}

4.2 做题思路

这道题目跟 全排列I 是不一样的,全排列I 中不存在重复的元素,但是这道题目中存在重复的元素,也就是说[1, 1, 2] 和 [1, 1, 2] 是同一个排列,这不看起来就是同一个排列吗?难道还能不同吗?其实这里的 1 不是同一个1,[1(下标为0), 1(下标为1), 2],[1(下标为1), 1(下标为0), 2],全排列I 中我们只需要使用一个标记数组来避免同一个元素被重复使用的情况,而这个 全排列II 中,我们还需要筛选出因元素相同而导致的相同排列的情况。那么如何筛选呢?我们来看个例子:

在这里插入图片描述

4.3 代码实现

class Solution {List<Integer> path;List<List<Integer>> ret;boolean[] vis;public List<List<Integer>> permuteUnique(int[] nums) {path = new ArrayList<>();ret = new ArrayList<>();vis = new boolean[nums.length];//首先将重复元素给排序到一起Arrays.sort(nums);dfs(nums);return ret;}private void dfs(int[] nums) {if (path.size() == nums.length) {ret.add(new ArrayList<>(path));return;}for (int i = 0; i < nums.length; i++) {if (vis[i] == false && (i == 0 || (nums[i - 1] != nums[i]) || vis[i - 1] == true)) {path.add(nums[i]);vis[i] = true;dfs(nums);//恢复现场path.remove(path.size() - 1);vis[i] = false;}}}
}

在这里插入图片描述

相关文章:

【算法系列篇】递归、搜索和回溯(四)

文章目录 前言什么是决策树1. 全排列1.1 题目要求1.2 做题思路1.3 代码实现 2. 子集2.1 题目要求2.2 做题思路2.3 代码实现 3. 找出所有子集的异或总和再求和3.1 题目要求3.2 做题思路3.3 代码实现 4. 全排列II4.1 题目要求4.2 做题思路4.3 代码实现 前言 前面我们通过几个题目…...

Windows 系统下本地单机搭建 Redis(一主二从三哨兵)

目录 一、Redis环境准备&#xff1a; 1、下载redis 2、Windows下的.msi安装和.zip格式区别&#xff1a; 二、哨兵介绍&#xff1a; 1、一主二从三哨兵理论图&#xff1a; 2.哨兵的主要功能&#xff1a; 3.哨兵用于实现 redis 集群的高可用&#xff0c;本身也是分布式的&…...

数据库访问被拒怎么操作?

就一点&#xff1a; &#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; cmd打开命令窗口直接输入 mysql -u root -p 然后加密码打开数据库服务再去试试&#xff01;&#xff01; &#xff01;&#xff01;&#xff01;&#xff01;&…...

Vue 2 生命周期即将结束

本文章翻译自 Vue 2 is Approaching End Of Life 文章原作者 youyuxi 2024 年即将到来&#xff0c;我们想借此机会提醒 Vue 社区&#xff0c;Vue 2 将于 2023 年 12 月 31 日达到生命周期结束 (EOL) Vue 2.0 于 2016 年发布&#xff0c;已有 7 年多的时间。这是 Vue 成为主流框…...

Python---端口和端口号的介绍

1. 问题思考 不同电脑上的飞秋之间进行数据通信&#xff0c;它是如何保证把数据给飞秋而不是给其它软件呢? 其实&#xff0c;每运行一个网络程序都会有一个端口&#xff0c;想要给对应的程序发送数据&#xff0c;找到对应的端口即可。 端口效果图: 2. 什么是端口 端口是传…...

Electron训练笔记

终端乱码解决办法&#xff1a;更改编号下载卡住解决办法&#xff1a;Electron RequestError: connect ETIMEDOUT 20.205.243.166:443electron本质是一个依赖库&#xff0c;改依赖库提供了部分对象&#xff0c;可以实现对于window的调用。electron有一个主进程&#xff0c;多个渲…...

2023 英特尔On技术创新大会直播 | 窥探未来科技的边界

2023 英特尔On技术创新大会直播 | 窥探未来科技的边界 写在最前面观后感其他有趣的专题课程 写在最前面 嘿&#xff0c;你是不是对科技和创新充满好奇&#xff1f;2023 英特尔 On 技术创新大会线上活动邀请你一起探索最前沿的科技世界&#xff01; 这不仅是一场普通的聚会&…...

机器学习之逻辑回归,一文掌握逻辑回归算法知识文集

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…...

H-ui前端框架 —— layer.js

layer.js是由前端大牛贤心编写的web弹窗插件。 laye.js是个轻量级的网页弹出层组件..支持类型丰富的弹出层类型&#xff0c;如消息框、页面层、iframe层等&#xff0c;具有较好的兼容性和灵活性。 layer.js用法 1.引入layer.js文件。在HTML页面的头部引用layer.is文件&#x…...

「Verilog学习笔记」游戏机计费程序

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 timescale 1ns/1nsmodule game_count(input rst_n, //异位复位信号&#xff0c;低电平有效input clk, //时钟信号input [9:0]money,input set,input boost,output reg[9:0…...

b站高可用架构 笔记

b站高可用架构 关键点&#xff1a;主机房&#xff0c;多活和多活机房 参考文章&#xff1a;bilibili技术总监毛剑&#xff1a;B站高可用架构实践 1. 前端和数据中心负载均衡 前端负载均衡(动态CDN):最近节点、带宽策略、可用服务容量 数据中心负载均衡:均衡流量、识别异常节…...

Android: Ubuntu下交叉环境编译常用调试工具demo for lspci命令(ARM设备)

lspci命令交叉环境编译(ARM设备) 交叉编译工具下载&#xff1a; https://releases.linaro.org/components/toolchain/binaries https://releases.linaro.org/components/toolchain/binaries/6.3-2017.05/aarch64-linux-gnu/ lspci命令交叉环境编译(ARM设备)&#xff1a; 1&a…...

《2023全球IPv6支持度白皮书》近日发布

近日&#xff0c;全球IPv6论坛联合中国的下一代互联网国家工程中心面向全球发布《2023全球IPv6支持度白皮书》。白皮书显示&#xff0c;在过去一年&#xff0c;全球IPv6支持度大幅提升&#xff0c;部署应用成效显著。全球IPv6部署率超过40%的国家数量同比增长了30%&#xff0c;…...

IDEA版SSM入门到实战(Maven+MyBatis+Spring+SpringMVC) -Spring的AOP前奏

第一章 AOP前奏 1.1 代理模式 代理模式&#xff1a;我们需要做一件事情&#xff0c;又不期望自己亲力亲为&#xff0c;此时&#xff0c;可以找一个代理【中介】 我们【目标对象】与中介【代理对象】不能相互转换&#xff0c;因为是“兄弟”关系 1.2 为什么需要代理【程序中…...

2023年度佳作:AIGC、AGI、GhatGPT 与人工智能大模型的创新与前景展望

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 写在前面参与规则 ✅参与方式&#xff1a;关注博主、点赞、收藏、评论&#xff0c;任意评论&#xff08;每人最多评论…...

直播电商“去网红化”势在必行,AI数字人打造品牌专属IP

近年来&#xff0c;网红直播带货“翻车”事件频发&#xff0c;给品牌商带来了信任危机和负面口碑的困扰&#xff0c;严重损害了企业的声誉。这证明强大的个人IP,对于吸引粉丝和流量确实能起到巨大的好处,堪称“金牌销售”,但太过强势的个人IP属性也会给企业带来一定风险&#x…...

Java如何开发PC客户端(Windows,Mac,Linux)

项目编译工具&#xff1a;Gradle开发工具&#xff1a; Idea开发语言&#xff1a; 建议java17以上ui组件&#xff1a;openjfx (org.openjfx.javafxplugin)打包工具: jpackage (org.beryx.jlink) 一、如何解决打包问题 java 14以后&#xff0c;有了jpackage工具&#xff0c;能够…...

热红外图像非均匀校正方法

热红外图像中的非均匀性通常指的是热像仪在感知温度时出现的空间上的灵敏度不均匀。这种非均匀性可能是由于热像仪本身的制造差异、温度梯度引起的热漂移、光学系统中的不均匀性等因素引起的。为了获得更准确、可靠的温度信息&#xff0c;需要进行非均匀校正。 原因&#xff1…...

性能压力测试--确保企业数字化业务稳健运行

随着企业的数字化转型和依赖云计算的普及&#xff0c;软件系统的性能已经成为企业成功运营的关键因素之一。性能压力测试作为确保系统在各种条件下都能高效运行的关键步骤&#xff0c;对企业的重要性不可忽视。以下是性能压力测试对企业的几个重要方面的影响和作用&#xff1a;…...

【Java】7种逻辑运算,你了解几种

嗨&#xff0c;朋友们&#xff01;今天我们聊点轻松的&#xff0c;来看看Java中那些常用的逻辑运算。可能你在学习编程的路上已经遇到过它们&#xff0c;但是让我们像闲聊一样&#xff0c;再重新认识一下这些小伙伴们&#xff01; 那个老实巴交的“与”&#xff08;AND&#x…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...