代码随想录算法训练营三刷day29 | 回溯算法之 491.递增子序列 46.全排列 47.全排列 II

三刷day29

      • 491.递增子序列
        • 回溯三部曲
      • 46.全排列
        • 回溯三部曲
      • 47.全排列 II

491.递增子序列

题目链接
解题思路:
在这里插入图片描述

回溯三部曲
  • 递归函数参数

本题求子序列,很明显一个元素不能重复使用,所以需要startIndex,调整下一层递归的起始位置。

代码如下:

vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, int startIndex)
  • 终止条件

本题其实类似求子集问题,也是要遍历树形结构找每一个节点,所以和回溯算法:求子集问题!一样,可以不加终止条件,startIndex每次都会加1,并不会无限递归。

但本题收集结果有所不同,题目要求递增子序列大小至少为2,所以代码如下:

if (path.size() > 1) {
    result.push_back(path);
    // 注意这里不要加return,因为要取树上的所有节点
}
  • 单层搜索逻辑
    在这里插入图片描述

递增子序列1 在图中可以看出,同一父节点下的同层上使用过的元素就不能再使用了

那么单层搜索代码如下:

unordered_set<int> uset; // 使用set来对本层元素进行去重
for (int i = startIndex; i < nums.size(); i++) {
    if ((!path.empty() && nums[i] < path.back())
            || uset.find(nums[i]) != uset.end()) {
            continue;
    }
    uset.insert(nums[i]); // 记录这个元素在本层用过了,本层后面不能再用了
    path.push_back(nums[i]);
    backtracking(nums, i + 1);
    path.pop_back();
}

对于已经习惯写回溯的同学,看到递归函数上面的uset.insert(nums[i]);,下面却没有对应的pop之类的操作,应该很不习惯吧,哈哈

这也是需要注意的点,unordered_set uset; 是记录本层元素是否重复使用,新的一层uset都会重新定义(清空),所以要知道uset只负责本层!

整体C++代码如下:

class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(vector<int>& nums, int startIndex) {
        if (path.size() > 1) {
            result.push_back(path);
        }
        int used[201] = {0}; // 这里使用数组来进行去重操作,题目说数值范围[-100, 100]
        for (int i = startIndex; i < nums.size(); i++) {
            if ((!path.empty() && nums[i] < path.back())
                    || used[nums[i] + 100] == 1) {
                    continue;
            }
            used[nums[i] + 100] = 1; // 记录这个元素在本层用过了,本层后面不能再用了
            path.push_back(nums[i]);
            backtracking(nums, i + 1);
            path.pop_back();
        }
    }
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        result.clear();
        path.clear();
        backtracking(nums, 0);
        return result;
    }
};

46.全排列

题目链接

解题思路:在这里插入图片描述

回溯三部曲
  • 递归函数参数

首先排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。

可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题就不用使用startIndex了。

但排列问题需要一个used数组,标记已经选择的元素,如图橘黄色部分所示:

46.全排列
代码如下:

vector<vector<int>> result;
vector<int> path;
void backtracking (vector<int>& nums, vector<bool>& used)
  • 递归终止条件

46.全排列

可以看出叶子节点,就是收割结果的地方。

那么什么时候,算是到达叶子节点呢?

当收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点。

代码如下:

// 此时说明找到了一组
if (path.size() == nums.size()) {
    result.push_back(path);
    return;
}
  • 单层搜索的逻辑

这里和77.组合问题131.切割问题 和78.子集问题最大的不同就是for循环里不用startIndex了。

因为排列问题,每次都要从头开始搜索,例如元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次1。

而used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次。

代码如下:

for (int i = 0; i < nums.size(); i++) {
    if (used[i] == true) continue; // path里已经收录的元素,直接跳过
    used[i] = true;
    path.push_back(nums[i]);
    backtracking(nums, used);
    path.pop_back();
    used[i] = false;
}

整体代码如下:

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking (vector<int>& nums, vector<bool>& used) {
        // 此时说明找到了一组
        if (path.size() == nums.size()) {
            result.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++) {
            if (used[i] == true) continue; // path里已经收录的元素,直接跳过
            used[i] = true;
            path.push_back(nums[i]);
            backtracking(nums, used);
            path.pop_back();
            used[i] = false;
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        result.clear();
        path.clear();
        vector<bool> used(nums.size(), false);
        backtracking(nums, used);
        return result;
    }
};


47.全排列 II

题目链接

class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking (vector<int>& nums, vector<bool>& used) {
        // 此时说明找到了一组
        if (path.size() == nums.size()) {
            result.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++) {
            // used[i - 1] == true,说明同一树枝nums[i - 1]使用过
            // used[i - 1] == false,说明同一树层nums[i - 1]使用过 
            // 如果同一树层nums[i - 1]使用过则直接跳过
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                continue;
            }
            if (used[i] == false) {
                used[i] = true;
                path.push_back(nums[i]);
                backtracking(nums, used);
                path.pop_back();
                used[i] = false;
            }
        }
    }
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        result.clear();
        path.clear();
        sort(nums.begin(), nums.end()); // 排序
        vector<bool> used(nums.size(), false);
        backtracking(nums, used);
        return result;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c语言指针(二)

文章目录 c语言指针&#xff08;二&#xff09;1.数组名的理解2.使用指针访问数组3.一维数组的传参本质 c语言指针&#xff08;二&#xff09; 1.数组名的理解 int arr[10] { 1,2,3,4,5,6,7,8,9,10 }; int* p &arr[0]这⾥我们使⽤ &arr[0] 的⽅式拿到了数组第⼀个元…

系统设计实例(一)百万级别用户系统

二、百万级别用户系统 原则&#xff1a; 尽可能地缓存数据采用无状态Web层支持多个数据中心在 CDN 中托管静态资源通过分片扩展数据层将层级拆分为独立的服务 负载均衡器 负载均衡器会将传入的流量均匀分配给在负载均衡集合中定义的Web服务器&#xff0c;用户直接连接负载均…

【C++ leetcode】双指针问题(续)

3. 202 .快乐数 题目 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。如果这个过程 结…

文件IO (File对象, 文件读写)

文件 狭义的文件: 硬盘上的文件和目录(文件夹) 广义的文件: 泛指计算机中的很多 软硬件资源 OS 中, 把很多硬件设备和软件资源抽象成了文件, 按照文件的方式来统一管理网络编程中, OS 把网卡当成了一个文件来操作 路径 绝对路径: 以盘符**(c: d: e:)**开头的路径 相对路径: 以 …

HarmonyOS ArkTS 通用事件(二十三)

通用事件目录 点击事件事件ClickEvent对象说明EventTarget8对象说明示例 触摸事件事件TouchEvent对象说明TouchObject对象说明示例 挂载卸载事件事件示例 点击事件 组件被点击时触发的事件。 事件 ClickEvent对象说明 从API version 9开始&#xff0c;该接口支持在ArkTS卡片中…

C++:继承:面向对象编程的重要特性

(❁◡❁)(●◡●)╰(*▽*)╯(*/ω&#xff3c;*)(^///^)(❁◡❁)(❁◡❁)(●◡●)╰(*▽*)╯(*/ω&#xff3c;*)(❁◡❁)(●’◡’●)╰(▽)╯(/ω&#xff3c;)(///) C&#xff1a;继承&#xff1a;面向对象编程的重要特性 前言**继承**1.继承的概念及定义1.1继承的概念1.2继…

学完Python的7大就业方向,哪个赚钱最多?

“ 我想学Python&#xff0c;但是学完Python后都能干啥 &#xff1f;” “ 现在学Python&#xff0c;哪个方向最简单&#xff1f;哪个方向最吃香 &#xff1f;” “ …… ” 相信不少Python的初学者&#xff0c;都会遇到上面的这些问题。大家都知道Python很吃香&#xff0c;薪资…

英伟达 V100、A100/800、H100/800 GPU 对比

近期&#xff0c;不论是国外的 ChatGPT&#xff0c;还是国内诸多的大模型&#xff0c;让 AIGC 的市场一片爆火。而在 AIGC 的种种智能表现背后&#xff0c;均来自于堪称天文数字的算力支持。以 ChatGPT 为例&#xff0c;据微软高管透露&#xff0c;为 ChatGPT 提供算力支持的 A…

slab分配器

什么是slab分配器&#xff1f; 用户态程序可以使用malloc及其在C标准库中的相关函数申请内存&#xff1b;内核也需要经常分配内存&#xff0c;但无法使用标准库函数&#xff1b;linux内核中&#xff0c;伙伴分配器是一种页分配器&#xff0c;是以页为单位的&#xff0c;但这个…

【考研数学】零基础全年可实操规划+网课资料分析

我理解的零基础就是一点基础也没有&#xff0c;甚至来呢最基础的求极限都不会 其实大家可以参照我的经验&#xff0c;零基础数学二&#xff0c;经过一年的学习学习&#xff0c;最后考了122分 首先大家要有自信&#xff0c;我都行你们肯定也可以&#xff01;其实考研数学真的没…

XCode升级错误:Command CompileC failed with a nonzero exit code 解决办法

升级完XCode之后&#xff0c;bulid失败&#xff0c;出现如下错误&#xff1a; 问题1&#xff1a; xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrunCommand Compi…

【性能测试】JMeter:集合点,同步定时器的应用实例!

一、集合点的定义 在性能测试过程中&#xff0c;为了真实模拟多个用户同时进行操作以度量服务器的处理能力&#xff0c;可以考虑同步虚拟用户以便恰好在同一时刻执行操作或发送请求。 通过插入集合点可以较真实模拟多个用户并发操作。 (注意&#xff1a;虽然通过加入集合点可…

2024藏在身边的冷门暴利行业,普通人掌握这个方式也能轻松加入赚取100万!适合普通人轻资产创业项目!2024新的创业机会

如果说2024创业圈流传最多的话是什么&#xff0c;那一定是&#xff1a;“阶级固化了&#xff0c;翻身太难”、“2024机会太少了&#xff0c;赚不到钱”、“经济大环境不好&#xff0c;创业寒冬”云云。 其实这些抱怨都是毫无道理的&#xff0c;无论是国内还是国外&#xff0c;对…

突破图神经网络技术瓶颈!新阶段3大创新方向大幅提高模型性能

针对传统的图神经网络在处理非结构化数据、捕捉高阶关系等方面的局限性&#xff0c;研究者们提出了众多优化方案。 这其中&#xff0c;超图神经网络、几何图神经网络、动态图神经网络作为GNN发展的前沿方向&#xff0c;不仅提供了更加丰富和灵活的方法来处理各种复杂的图数据&…

基于ssm的航空售票系统

基于SSM的航空订票系统根据功能设计划分为管理员用户和注册用户&#xff0c;从这两种用户的功能所需展开设计&#xff0c;管理员对注册用户管理、航班管理、航班时刻管理、通知公告管理、订票管理、退票管理等&#xff1b;注册用户主要是注册成功后登录&#xff0c;机票查询&am…

基于 Vue3打造前台+中台通用提效解决方案(中)

33、实现全屏展示功能 我们知道在原生dom上,提供了一些方法来供我们开启或关闭全屏: Element.requestFullscreen()Document.exitFullscreen()Document.fullscreenDocument.fullscreenElement一般浏览器 使用requestFullscreen()和exitFullscreen()来实现 早期版本Chrome浏…

异常:程序出现的问题

目的&#xff1a;为了以后发现异常后怎么去处理 异常的作用

学点儿Java_Day7_在实体类当中IDEA无法进行单元测试(@Test没有启动按钮)

在敲代码体会继承和访问修饰符的时候忽然遇到了单元测试不管用的情况&#xff0c;表现为没有启动按钮   经过一番折腾&#xff0c;发现我的测试是在具有构造函数的实体类Person当中进行的&#xff0c;当我把所有的构造函数删除后&#xff0c;启动按钮又出来了&#xff0c;加…

鸿蒙开发实战:【文件管理】

介绍 本示例主要展示了文件管理相关的功能&#xff0c;使用[ohos.multimedia.medialibrary]、[ohos.filemanagement.userFileManager] 、[ohos.fileio] 、[ohos.file.fs]、[ohos.app.ability.contextConstant] 等接口&#xff0c;实现了增添文件、删除文件、查找指定类型文件…

Java基础夯实——八股文【2024面试题案例代码】

1、Java当中的基本数据类型 Java中常见的数据类型及其对应的字节长度和取值范围如下&#xff1a; byte&#xff1a;1字节&#xff0c;取值范围为-128到127。short&#xff1a;2字节&#xff0c;取值范围为-32,768到32,767。int&#xff1a;4字节&#xff0c;取值范围为-2,147…