代码随想录刷题day29|非递减子序列全排列全排列II

文章目录

  • day29学习内容
  • 一、非递减子序列
    • 1.1、代码-错误写法
      • 1.1.1 多了一个return语句。
      • 1.1.2、nums[i-1] > nums[i],这个条件写错了,为什么呢?
        • 1. 忽略了回溯算法的动态决策过程
        • 2. 限制了可能的递增子序列的探索
    • 1.2、代码-正确写法
  • 二、全排列
    • 2.1、科普
    • 2.2、错误写法
    • 2.3、正确写法1
  • 三、全排列II
    • 3.1、思路
    • 3.2、代码-正确写法
  • 总结
    • 1.感想
    • 2.思维导图


day29学习内容

day29主要内容

  • 非递减子序列
  • 全排列
  • 全排列II

声明
本文思路和文字,引用自《代码随想录》

一、非递减子序列

491.原题链接

1.1、代码-错误写法

class Solution {List<List<Integer>> result = new ArrayList();List<Integer> path = new ArrayList();public List<List<Integer>> findSubsequences(int[] nums) {backTracking(nums, 0);return result;}private void backTracking(int[] nums, int startIndex) {// 终止条件if (path.size() >= 2) {result.add(new ArrayList(path));return;}// 用一个set判断是否已经使用过HashSet<Integer> set = new HashSet<>();// 遍历for (int i = startIndex; i < nums.length; i++) {// 如果递归时下一层节点的值比子序列最后一个元素值大,不满足递增,所以要返回// 或者之前已经使用过该元素if (!path.isEmpty() && nums[i-1] > nums[i] || set.contains(nums[i])) {continue;}// 单层递归逻辑path.add(nums[i]);set.add(nums[i]);// 递归backTracking(nums, i + 1);// 回溯path.remove(path.size() - 1);}}
}

这种写法有2个地方都是错误的。

1.1.1 多了一个return语句。

if (path.size() >= 2) {result.add(new ArrayList(path));return;}

目的是找到所有可能的递增子序列:目标是列出所有可能的递增子序列,而不仅仅是找到第一个满足条件的子序列后就停止。因此,在找到一个有效子序列并将其添加到结果集后,不应该立即返回,而应该继续探索其他可能的子序列。直接返回会导致漏掉其他有效的子序列组合。

回溯算法的工作机制:在执行回溯算法时,每一次递归调用代表探索决策树的一个分支。当达到一个终结点(即满足特定条件的点)时,我们会记录下当前的路径作为结果之一,然后通过回溯(撤销最后的选择)返回到前一个状态,继续探索其他可能的分支。如果在添加结果后立即返回,那么就会错过从当前点出发的其他潜在路径。

1.1.2、nums[i-1] > nums[i],这个条件写错了,为什么呢?

注意看老师画的图,是递归的时候比较的。即下一层节点的值比子序列最后一个元素值大,如果比之前的大,就不满足递增了。
确实,针对解释原因2和3,使用数组[3, 4, 1, 5]作为例子可能会更加合适和清晰。这里我们使用这个数组来重新说明原因2和3,以展示为何不应使用nums[i-1] > nums[i]作为判断条件。

1. 忽略了回溯算法的动态决策过程
  • 例子:考虑数组[3, 4, 1, 5]
    • 在进行到4之后,下一个元素是1。如果使用nums[i-1] > nums[i]4 > 1作为理由停止当前探索,那么我们将错过以1作为起始点、且包含5的递增子序列[1, 5]
    • 这个例子展示了即使当前元素相对于前一个元素是递减的,它仍然可能是未来某个有效递增子序列的起点。
2. 限制了可能的递增子序列的探索
  • 例子:同样考虑数组[3, 4, 1, 5]
    • 如果我们在遍历到4后面的1时,仅因为4 > 1就停止探索,那么我们不仅错过了以1开始的递增子序列,还错过了整个数组中存在的一个非常明显的递增子序列[3, 4, 5]
    • 正确的逻辑应该是,即使1相对于4是递减的,我们仍然继续探索,因为1后面的5可以与数组中的其他元素(如34)形成有效的递增子序列。

1.2、代码-正确写法

class Solution {List<List<Integer>> result = new ArrayList();List<Integer> path = new ArrayList();public List<List<Integer>> findSubsequences(int[] nums) {backTracking(nums, 0);return result;}private void backTracking(int[] nums, int startIndex) {// 终止条件if (path.size() >= 2) {result.add(new ArrayList(path));}// 用一个set判断是否已经使用过HashSet<Integer> set = new HashSet<>();// 遍历for (int i = startIndex; i < nums.length; i++) {// 如果递归时下一层节点的值比子序列最后一个元素值大,不满足递增,所以要返回// 或者之前已经使用过该元素if (!path.isEmpty() && path.get(path.size() - 1) > nums[i] || set.contains(nums[i])) {continue;}// 单层递归逻辑path.add(nums[i]);set.add(nums[i]);// 递归backTracking(nums, i + 1);// 回溯path.remove(path.size() - 1);}}
}

二、全排列

46.原题链接

2.1、科普

[1,2]和[2,1]是同一个排列

2.2、错误写法

class Solution {List<List<Integer>> result = new ArrayList();List<Integer> path = new ArrayList();public List<List<Integer>> permute(int[] nums) {backTraking(nums);return result;}private void backTraking(int nums[]) {if (path.size() > nums.length) {return;}if (path.size() == nums.length) {result.add(new ArrayList(path));}for (int i = 0; i < nums.length; i++) {path.add(nums[i]);// 递归backTraking(nums);path.remove(path.size() - 1);}}
}
  • 为什么是错的
  • 在这里插入图片描述
    看图很明显了,有重复数据,没有进行去重。

2.3、正确写法1

class Solution {List<List<Integer>> result = new ArrayList();List<Integer> path = new ArrayList();//用数组标识是否使用过boolean[] used;public List<List<Integer>> permute(int[] nums) {// 初始化数组used = new boolean[nums.length];backTraking(nums);return result;}private void backTraking(int nums[]) {if (path.size() > nums.length) {return;}if (path.size() == nums.length) {result.add(new ArrayList(path));}for (int i = 0; i < nums.length; i++) {if (used[i]) {continue;}path.add(nums[i]);used[i] = true;// 递归backTraking(nums);used[i] = false;path.remove(path.size() - 1);}}
}

三、全排列II

47.原题链接

3.1、思路

  • 看麻了,代码抄的题解
  • 简单的说,就是在46题的基础上,加了一个去重的逻辑
  • 回溯逻辑(backTraking方法)
  • 终止条件:如果path的大小与nums数组的长度相同,意味着已经找到了一个完整的排列,将其添加到result中,并返回。
  • 循环和选择:遍历每个元素,尝试将其添加到当前路径(path)中。
  • 去重判断:if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) { continue; }
    • 这个条件是去重的核心逻辑。当前元素与前一个元素相同,且前一个元素还未被使用(意味着是在回溯的过程中,而不是在向下构建路径的过程中),则跳过当前元素。
      • 这是因为在这种情况下,选择当前元素会产生与之前处理过的元素相同的排列,从而导致重复。
    • 未使用的元素:如果当前元素未被使用,则将其添加到路径中,并标记为已使用,然后递归地继续构建排列,之后撤销这一选择以尝试其他选项。
  • 回溯的撤销操作
    • 在递归调用返回后,执行撤销操作:从路径中移除最近添加的元素,并将used[i]重新标记为false。这一步是回溯算法的典型做法,它确保了在探索完一个元素所有可能性之后,能够正确地恢复状态,并探索下一个元素的所有可能性。

3.2、代码-正确写法

class Solution {List<List<Integer>> result = new ArrayList();List<Integer> path = new ArrayList();// 用数组标识是否使用过boolean[] used;public List<List<Integer>> permuteUnique(int[] nums) {// 初始化数组used = new boolean[nums.length];Arrays.sort(nums);backTraking(nums);return result;}private void backTraking(int nums[]) {if (path.size() == nums.length) {result.add(new ArrayList(path));return;}for (int i = 0; i < nums.length; i++) {if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {continue;}if (used[i] == false) {path.add(nums[i]);used[i] = true;// 递归backTraking(nums);used[i] = false;path.remove(path.size() - 1);}}}
}

看麻了这一题。。

总结

1.感想

  • 马上就是连续刷题一个月了,加油。

2.思维导图

本文思路引用自代码随想录,感谢代码随想录作者。

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

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

相关文章

还是了解下吧,大语言模型调研汇总

大语言模型调研汇总 一. Basic Language ModelT5GPT-3LaMDAJurassic-1MT-NLGGopherChinchillaPaLMU-PaLMOPTLLaMABLOOMGLM-130BERNIE 3.0 Titan 二. Instruction-Finetuned Language ModelT0FLANFlan-LMBLOOMZ & mT0GPT-3.5ChatGPTGPT-4AlpacaChatGLMERNIE BotBard 自从Cha…

wayland(xdg_wm_base) + egl + opengles 渲染使用纹理贴图的旋转 3D 立方体实例(十三)

文章目录 前言一、使用 stb_image 库加载纹理图片1. 获取 stb_image.h 头文件2. 使用 stb_image.h 中的相关接口加载纹理图片3. 纹理图片——cordeBouee4.jpg二、渲染使用纹理贴图的旋转 3D 立方体1. egl_wayland_texture_cube.c2. Matrix.h 和 Matrix.c3. xdg-shell-client-pr…

浅谈大模型“幻觉”问题

大模型的幻觉大概来源于算法对于数据处理的混乱&#xff0c;它不像人类一样可以by the book&#xff0c;它没有一个权威的对照数据源。 什么是大模型幻觉 大模型的幻觉&#xff08;Hallucination&#xff09;是指当人工智能模型生成的内容与提供的源内容不符或没有意义的现象。…

【JavaScript】JavaScript 程序流程控制 ② ( 循环流程控制 | 循环要素 - 循环体 / 循环终止条件 | for 循环语法结构 )

文章目录 一、JavaScript 程序流程控制 - 循环流程控制1、循环流程控制2、循环要素 - 循环体 / 循环终止条件3、for 循环语法结构 - 循环控制变量 / 循环终止条件 / 操作表达式4、for 循环 完整代码示例 一、JavaScript 程序流程控制 - 循环流程控制 1、循环流程控制 在 程序开…

C# 连接neo4j数据库,包括非默认的neo4j默认库

官方文档没找见&#xff0c;自己在源码里面找到的 private string _dbHost "bolt://localhost:7687"; private string _dbUser "neo4j"; private string _dbPassword "******"; private IDriver? _driver;public CQLOperation(string _data…

CTF-reverse-每日练题-xxxorrr

题目链接 https://adworld.xctf.org.cn/challenges/list 题目详情 xxxorrr ​ 解题报告 下载得到的文件使用ida64分析&#xff0c;如果报错就换ida32&#xff0c;得到分析结果&#xff0c;有main函数就先看main main函数分析 v6 main函数中&#xff0c;v6的值是__readfsqwor…

Haproxy 负载均衡集群

一. Haproxy &#xff1a; 1. Haproxy 介绍&#xff1a; HAProxy 是法国开发者威利塔罗 (Willy Tarreau) 在2000年使用C语言开发的一个开源软件&#xff0c;是一款具备高并发(一万以上)、高性能的TCP和HTTP负载均衡器&#xff0c;支持基于cookie的持久性&#xff0c;自动故障…

河南大学大数据平台技术实验报告二

大数据平台技术课程实验报告 实验二&#xff1a;HDFS操作实践 姓名&#xff1a;杨馥瑞 学号&#xff1a;2212080042 专业&#xff1a;数据科学与大数据技术 年级&#xff1a;2022级 主讲教师&#xff1a;林英豪 实验时间&#xff1a;2024年3月15日3点 至 2024年3月15日4点40 …

【矩阵】54. 螺旋矩阵【中等】

螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 解题思路 1、模拟顺时针螺旋顺序遍历矩阵…

完美解决 RabbitMQ可视化界面Overview不显示折线图和队列不显示Messages

问题场景&#xff1a; 今天使用docker部署了一个RabbitMQ&#xff0c;浏览器打开15672可视化页面发送消息后不显示Overview中的折线图&#xff0c;还有队列中的Messages&#xff0c;因为我要看队列中的消息数量。 解决方案&#xff1a; 进入容器内部 docker exec -it 容器id…

视频素材库app推荐的地方在哪里找?

视频素材库app推荐的地方在哪里&#xff1f;这是很多短视频创作者都会遇到的问题。别着急&#xff0c;今天我就来给大家介绍几个视频素材库app推荐的网站&#xff0c;让你的视频创作更加轻松有趣&#xff01; 蛙学网&#xff1a;视频素材库app推荐的首选当然是蛙学网啦&#xf…

CommonJs规范

文章目录 1. CommonJS 模块的导出2. CommonJS 模块的导入2.1使用 require 函数导入文件模块&#xff08;用户自定义&#xff09;2.2使用 require 函数导入核心模块&#xff08;Node.js 内置的模块&#xff09;2.3文件夹作为模块2.4模块的原理 在node中&#xff0c;默认支持的模…

GPT-4引领AI新纪元,Claude3、Gemini、Sora能否跟上步伐?

【最新增加Claude3、Gemini、Sora、GPTs讲解及AI领域中的集中大模型的最新技术】 2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚…

C语言——自定义类型——结构体(从零到一的跨越)

目录 前言 1.什么是结构体 2.结构体类型的声明 2.1结构体的声明 2.2结构体的创建和初始化 2.3结构成员访问操作符 2.3.1结构体成员直接访问 2.3.2结构体成员的间接访问 2.4结构体变量的重命名 2.5结构体的特殊声明 2.6结构的自引用 3.结构体内存对齐 3.1对齐规则 3…

JMH微基准测试框架学习笔记

一、简介 JMH&#xff08;Java Microbenchmark Harness&#xff09;是一个用于编写、构建和运行Java微基准测试的框架。它提供了丰富的注解和工具&#xff0c;用于精确控制测试的执行和结果测量&#xff0c;从而帮助我们深入了解代码的性能特性。 二、案例实战 在你的pom文件…

数据结构从入门到精通——直接选择排序

直接选择排序 前言一、选择排序的基本思想&#xff1a;二、直接选择排序三、直接选择排序的特性总结&#xff1a;四、直接选择排序的动画展示五、直接选择排序的代码展示test.c 六、直接选择排序的优化test.c 前言 直接选择排序是一种简单的排序算法。它的工作原理是每一次从未…

Hadoop大数据应用:HDFS 集群节点缩容

目录 一、实验 1.环境 2.HDFS 集群节点缩容 二、问题 1.数据迁移有哪些状态 2.数据迁移失败 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 主机架构软件版本IP备注hadoop NameNode &#xff08;已部署&#xff09; SecondaryNameNode &#xff08;已部署…

Epuck2机器人固件更新及IP查询

文章目录 前言一、下载固件更新软件包&#xff1a;二、查询机器人在局域网下的IP 前言 前面进行了多机器人编队仿真包括集中式和分布式&#xff0c;最近打算在实物机器人上跑一跑之前的编队算法。但由于Epuck2机器人长时间没使用&#xff0c;故对其进行固件的更新&#xff0c;…

直播预约丨《袋鼠云大数据实操指南》No.1:从理论到实践,离线开发全流程解析

近年来&#xff0c;新质生产力、数据要素及数据资产入表等新兴概念犹如一股强劲的浪潮&#xff0c;持续冲击并革新着企业数字化转型的观念视野&#xff0c;昭示着一个以数据为核心驱动力的新时代正稳步启幕。 面对这些引领经济转型的新兴概念&#xff0c;为了更好地服务于客户…

CTF题型 匿名函数考法例题总结

CTF题型 匿名函数考法&例题总结 文章目录 CTF题型 匿名函数考法&例题总结一 .原理分析二 .重点匿名函数利用1.create_function()如何实现create_function代码注入 2.array_map()3.call_user_func()4.call_user_func_array()5.array_filter() 三.例题讲解1.[Polar 靶场 …