代码随想录算法训练营第 25 天 | LeetCode491.递增子序列 LeetCode46.全排列 LeetCode47.全排列ii

代码随想录算法训练营

Day25代码随想录算法训练营第 25 天 | LeetCode491.递增子序列 LeetCode46.全排列 LeetCode47.全排列ii


目录

  • 代码随想录算法训练营
  • 前言
    • LeetCode491.递增子序列
    • LeetCode46.全排列
    • LeetCode47.全排列ii
  • 一、LeetCode491.递增子序列
    • 1.题目链接
    • 2.思路
    • 3.题解
  • 二、LeetCode46.全排列
    • 1.题目链接
    • 2.思路
    • 3.题解
  • 三、LeetCode47.全排列 II
    • 1.题目链接
    • 2.思路
    • 3.题解
  • 总结


前言

LeetCode491.递增子序列

讲解文档

LeetCode46.全排列

讲解文档

LeetCode47.全排列ii

讲解文档


一、LeetCode491.递增子序列

1.题目链接

LeetCode491.递增子序列

2.思路

(1)这道题和子集很像,都是保存大部分节点,所以保存答案是单层递归的一部分,每层保存一次答案,保存答案以后不进行返回
(注意,如果要写边界条件返回,要写在保存答案的后面,否则达到边界条件的答案无法保存)
(2)这道题和子集也有不同
1)不能预先排序
2)去重的操作不同:由于不能预先排序,所以不能用子集问题的与前一个元素比较的方法判断重复,只能用哈希表记录是否在同一层用过

  • 这道题要求不能有重复的组合,所以同一层不能用同样的数字
  • 数字范围[-100,100],用数组实现哈希表。我们将数字映射成数组下标:nums[i]+100
  • used数组在单层递归中定义,每一层都有自己used数组,所以回溯后不要把used数组变成0

3.题解

class Solution {
public:vector<vector<int>> res;vector<int> path;void func(vector<int>& nums, int start) {if (path.size() >= 2) {res.push_back(path);}int used[205] = {0};for (int i = start; i < nums.size(); i++) {if (path.size() && path.back() > nums[i] || used[nums[i] + 100])continue;path.push_back(nums[i]);used[nums[i] + 100] = 1;func(nums, i + 1);path.pop_back();}}vector<vector<int>> findSubsequences(vector<int>& nums) {func(nums, 0);return res;}
};

二、LeetCode46.全排列

1.题目链接

LeetCode46.全排列

2.思路

(1)参数:
为什么不用start:因为start在组合类问题里控制开始遍历的下标,而排列添加元素的顺序不一定是从前向后
(2)边界条件:
path里面包含所有元素时,存答案并返回
(3)单层递归
从头到尾遍历nums
1)如果元素已经在排列里面,跳过
2)used标记为true,加入排列
3)递归
4)回溯,used标记为false

3.题解

class Solution {
public:vector<vector<int>> res;vector<int> path;vector<bool> used;void func(vector<int>& nums) {if (path.size() == nums.size()) {res.push_back(path);return;}for (int i = 0; i < nums.size(); i++) {if (used[i])continue;path.push_back(nums[i]);used[i] = true;func(nums);used[i] = false;path.pop_back();}}vector<vector<int>> permute(vector<int>& nums) {for (int i = 0; i < nums.size(); i++) {used.push_back(false);}func(nums);return res;}
};

三、LeetCode47.全排列 II

1.题目链接

LeetCode47.全排列 II

2.思路

(1)与前一题区别在nums有重复元素,所以要去重,确保不会有重复的排列(重复的树枝)
(2)去重的两种方法
1)树层去重:避免在同一个树层讨论同一个数字
参考组合ii和子集ii的去重
如果元素和上一个元素相等,并且上一个元素在排列没出现,将在同一层竞争,跳过

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

树层去重
树层去重
2)树枝去重

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

树枝去重

树枝去重示意图

3.题解

树层去重

class Solution {
public:vector<vector<int>> res;vector<int> path;vector<bool> used;void func(vector<int>& nums) {if (nums.size() == path.size()) {res.push_back(path);return;}for (int i = 0; i < nums.size(); i++) {if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false)continue;if (used[i])continue;used[i] = true;path.push_back(nums[i]);func(nums);path.pop_back();used[i] = false;}}vector<vector<int>> permuteUnique(vector<int>& nums) {sort(nums.begin(), nums.end());for (int i = 0; i < nums.size(); i++) {used.push_back(false);}func(nums);return res;}
};

树枝去重

class Solution {
public:vector<vector<int>> res;vector<int> path;vector<bool> used;void func(vector<int>& nums) {if (nums.size() == path.size()) {res.push_back(path);return;}for (int i = 0; i < nums.size(); i++) {if (i > 0 && nums[i] == nums[i - 1] && used[i - 1])continue;if (used[i])continue;used[i] = true;path.push_back(nums[i]);func(nums);path.pop_back();used[i] = false;}}vector<vector<int>> permuteUnique(vector<int>& nums) {sort(nums.begin(), nums.end());for (int i = 0; i < nums.size(); i++) {used.push_back(false);}func(nums);return res;}
};

总结

  • 注意数字去重和元素去重:
    元素去重:元素下标=used数组下标
    数字去重:数字映射成used数组下标

  • 区分分割/组合和子集问题
    分割组合:保存叶节点,将保存答案看作边界条件处理的一部分,保存后返回
    子集问题:保存所有节点,将保存答案看作单层递归的一部分,保存后不返回
    子集问题注意把保存答案写在返回的前面

  • 排列和组合在写法上不同

    • 排列不需要start,因为每次都从头到尾全部遍历nums
    • 排列需要全局定义used数组标记是否在排列里用了
  • 去重问题
    子集、组合、全排列和子集ii、组合ii、全排列ii的区别是后者的nums有重复元素,然而我们不希望收集到重复的子集、组合、元素

  • 如果能预先排序,则先排序,全局定义used数组,用下面的代码判断是否重复

if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false)continue;
  • 如果不可以预先排序,则在每次递归定义used数组,如果used 为真,说明本层用过对应的元素了,跳过。回溯的时候不要把used变回false

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

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

相关文章

【算法】单向环形链表解决Josephu(约瑟夫)问题

应用场景 n 个小孩标号&#xff0c;逆时针站一圈。从 k 号开始&#xff0c;每一次从当前的小孩逆时针数 m 个&#xff0c;然后让最后这个小孩出列。不断循环上述过程&#xff0c;直到所有小孩出列&#xff0c;由此产生出一个队列编号。 提示 用一个不带头节点的循环链表来处…

FPGA开发——状态机的使用

一、概述 我们在使用FPGA进行开发的过程当中&#xff0c;实现一个东西用得最多的实现方法就是状态机的实现方法&#xff0c;用一句话总结就是万物皆可状态机&#xff0c;这和我们在学习Linux时常说的在Linux中万物都是文件差不多&#xff0c;这里就主要就是突出状态机的应用范…

技术实践—微前端技术应用

微前端是一种新兴的前端架构模式&#xff0c;是一种类似于微服务的架构&#xff0c;将微服务的理念应用于浏览器端。其核心理念是将一个大而单一的前端应用拆分为多个小型独立的微应用。这些微应用各自独立&#xff0c;可以由不同团队开发维护&#xff0c;部署&#xff0c;组合…

【调色板软件】免费、开源的调色板软件,焰火十二卷,提供了多种功能来生成一组调和色彩NO.108

本文一共:316 个字,需要阅读:1 分钟,更新时间:2024年7 月27日,部分内容具有时效性,如有失效请留言,阅读量:0 使用平台&#xff1a; Windows/macOS/CentOS/Ubuntu 由于我不是很懂&#xff0c;有需要的人自己摸索吧 资源来源于网络&#xff0c;免费分享仅供学习和测试使用&…

PostgreSQL 中如何重置序列值:将自增 ID 设定为特定值开始

我是从excel中将数据导入&#xff0c;然后再通过sql插入数据&#xff0c;就报错。 需要设置自增ID开始值 1、确定序列名称&#xff1a; 首先&#xff0c;需要找到与的增字段相关的序列名称。假设表名是 my_table 和自增字段是 id&#xff0c;可以使用以下查询来获取序列名称…

C 语言动态链表

线性结构->顺序存储->动态链表 一、理论部分 从起源中理解事物&#xff0c;就是从本质上理解事物。 -杜勒鲁奇 动态链表是通过结点&#xff08;Node&#xff09;的集合来非连续地存储数据&#xff0c;结点之间通过指针相互连接。 动态链表本身就是一种动态分配内存的…

【深度学习】LLaMA-Factory 大模型微调工具, 大模型GLM-4-9B Chat ,微调与部署 (2)

文章目录 数据准备chat评估模型导出模型部署总结 资料&#xff1a; https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md https://www.53ai.com/news/qianyanjishu/2015.html 代码拉取&#xff1a; git clone https://github.com/hiyouga/LLaMA-Factory.git cd …

万物互联,触手可及“2024南京智慧城市,物联网,大数据展会”

在金秋送爽的11月&#xff0c;南京这座历史悠久而又充满活力的城市&#xff0c;即将迎来一场科技盛宴——2024南京智慧城市、物联网、大数据展会。这不仅是一场技术的集会&#xff0c;更是未来生活蓝图的预览&#xff0c;它汇聚了全球顶尖的科技企业、创新者及行业精英&#xf…

【C++】循环结构-while语句

while 语句的语法格式&#xff1a; while (循环条件) {在满足循环条件下执行的操作} 注意要留有跳出循环的方式&#xff0c;避免死循环 1、不写 whlie (1)&#xff0c;写具体的循环条件 2、写while(1)&#xff0c;用 break 跳出循环 下面是一个实例 #include<iostream…

邮件攻击案例系列三:动态 IP 池爆破员工邮箱钓鱼重要客户

案例描述 2023 年 11 月&#xff0c;某制造业企业员工 Emily 接到海外客户电话&#xff0c;向其核实一封电子邮件的真实性&#xff0c;因为客户认为&#xff0c;该邮件所给出的链接不像是该公司的官网网址。Emily 查看自己的邮箱&#xff0c;并未发现客户所说的邮件。但从客户…

数据结构-----对列

前言 Hello, 小伙伴们&#xff0c;你们的作者菌又来了&#xff0c;前不久&#xff0c;我们学习了一种数据结构----栈&#xff0c;他特殊的性质使得他在一些数据管理的问题上被广泛的使用&#xff0c;那今天&#xff0c;我们就来学习另一种十分重要的数据结构--对列。 在开始之…

Linux字符设备驱动基本框架

本章我们从 Linux 驱动开发中最基础的字符设备驱动开始&#xff0c;重点学习 Linux 下字符设备驱动开发框架。本章会以一个虚拟的设备为例&#xff0c;讲解如何进行字符设备驱动开发&#xff0c;以及如何编写测试 APP 来测试驱动工作是否正常&#xff0c;为以后的学习打下坚实的…

3. 系统上电启动流程

1. 概述 上电启动&#xff0c;可参考恒玄sdk的指导手册。 注&#xff1a;可以在sdk这里加载自己的入口函数 STEP1&#xff1a; STEP2&#xff1a; STEP3&#xff1a; STEP4&#xff1a;

【日常记录】【插件】多媒体文本化: text-image 可以将文字、图片、视频进行「文本化」

文章目录 1. html基本结构2. 画文字3. 画图片4. 画视频参考地址 1. html基本结构 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-s…

ctfshow web入门 中期测评 web492--web502

web492 <?php include(render/render_class.php); include(render/db_class.php);$action$_GET[action]; if(!isset($action)){header(location:index.php?actionlogin);die(); }if($actioncheck){extract($_GET);if(preg_match(/^[A-Za-z0-9]$/, $username)){$sql &qu…

如何设置postgresql数据库的账户密码

说明&#xff1a;在我的云服务器上&#xff0c;postgres是使用yum的方式安装的&#xff0c;不需要设置postgres账户的密码&#xff0c;本文介绍安装后如何手动设置postgres账户的密码&#xff1b; postgres数据库安装&#xff0c;参考下面这篇文章&#xff1a; PostgreSQL安装…

SpringBoot整合SSE技术详解

Hi &#x1f44b;, Im shy SpringBoot整合SSE技术详解 1. 引言 在现代Web应用中,实时通信变得越来越重要。Server-Sent Events (SSE)是一种允许服务器向客户端推送数据的技术,为实现实时更新提供了一种简单而有效的方法。本文将详细介绍如何在SpringBoot中整合SSE,并探讨S…

python-学生排序(赛氪OJ)

[题目描述] 已有 a、b 两个链表&#xff0c;每个链表中的结点包括学号、成绩。要求把两个链表合并&#xff0c;按学号升序排列。输入格式&#xff1a; 输入共 NM1 行。 第一行&#xff0c;输入 a、b 两个链表元素的数量 N、M&#xff0c;中间用空格隔开。下来 N 行&#xff0c;…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第四十章 Linux用户层和内核层

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

找工作准备刷题Day10 回溯算法 (卡尔41期训练营 7.24)

回溯算法今天这几个题目做过&#xff0c;晚上有面试&#xff0c;今天水一水。 第一题&#xff1a;Leetcode77. 组合 题目描述 解题思路 从题目示例来看&#xff0c;k个数是不能重合的&#xff0c;但是题目没有明确说明这一点。 使用回溯算法解决此问题&#xff0c;利用树形…