代码随想录DAY25 - 回溯算法 - 08/24

news2024/9/20 12:37:16

目录

非递减子序列

题干

思路和代码

递归法

递归优化

全排列

题干

思路和代码

递归法

全排列Ⅱ

题干

思路和代码

方法一:用集合 set 去重

方法二:先排序,再用数组去重


非递减子序列

题干

题目:给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中至少有两个元素 。你可以按 任意顺序 返回答案。数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

示例 1:

输入:nums = [4,6,7,7] 输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]

示例 2:

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

说明:

  • 给定数组的长度不会超过15。

  • 数组中的整数范围是 [-100,100]。

  • 给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。

注意:原数组 nums 不一定有序!

链接:. - 力扣(LeetCode)

思路和代码

这道题可以在整数数组中找子集的基础上进行调整,我们可以先找出子集大小大于等于 2 的所有子集,若子集满足非递减序列,则插入结果中。同时,数组中可能含有重复元素,因此我们需要进行去重。和之前的去重操作类似,我们需要在树层去重,而不是树枝去重,即在同一层 for 循环中进行去重,而不是对递归去重。注意:我们不可以对数组 nums 进行排序,不然会改变元素的顺序,求出的递增子序列也不同。

递归法
  • 递归参数和返回值:参数是传入的整数数组和本层递归的起始位置 startIndex,无返回值。

  • 递归结束条件:当遍历完整个数组则返回,写不写终止条件都可以。

  • 递归顺序:先判断当前元素是否满足递增序列,且是否不和之前的元素重复,若满足递增且不重复,则继续递归后续的整数数组寻找递增子序列。

class Solution {
public:
    vector<int> composition;
    vector<vector<int>> result;
    void backTracking(vector<int> &nums, int startIndex){
        if (composition.size() >= 2) result.push_back(composition); // 子集大小大于等于2,才插入结果
		// 写不写终止条件都可以
        unordered_set<int> usedValue; // !!!记录在同一层 for 循环中使用过的 Value
        for (int i = startIndex; i < nums.size(); ++i) {
            if (!composition.empty() && nums[i] < composition.back()){ // 违反递增顺序,continue
                continue; // 因为后续可能还有元素,所以并不 return,而是 continue
            }
            if (usedValue.find(nums[i]) != usedValue.end()) continue; // 去重!
            composition.push_back(nums[i]);
            usedValue.insert(nums[i]); // 插入遍历过的元素
            backTracking(nums,i+1);
            composition.pop_back();
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backTracking(nums,0);
        return result;
    }
};
递归优化

我们在上一个方法中,用了 unordered_map 来记录遍历过的元素,程序运行的时候对 unordered_set 频繁的insert,相对费时间。而本题中数组的元素范围是[-100,100],范围并不大,因此可以用数组直接做哈希映射,效率会提高。

设定一个大小为 201 的 bool 型数组,下标为 0~200,元素 -100 映射到下标为0的数组空间中,元素 100 映射到下标为200的数组空间。

class Solution {
public:
    vector<int> composition;
    vector<vector<int>> result;
    void backTrack(vector<int> &nums, int startIndex){
        if (composition.size() >= 2) result.push_back(composition);
        // 终止条件写不写都行
        bool isUsed[201] = {false}; // 记录元素在同一层 for 循环是否被使用过,初始化为 false
        for (int i = startIndex; i < nums.size(); ++i) {
            if (!composition.empty() && nums[i] < composition.back()) continue;
            if (isUsed[nums[i]+100]) continue; // 若被使用过,则去重,跳过
            composition.push_back(nums[i]);
            isUsed[nums[i]+100] = true; // 修改当前元素的使用状态
            backTrack(nums,i+1);
            composition.pop_back();
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backTrack(nums,0);
        return result;
    }
};

全排列

题干

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

链接:. - 力扣(LeetCode)

思路和代码

递归法

全排列中,每个排列的大小是固定的,我们递归进入下一个排列的位置,for 循环改变该排列位置上的元素。

  • 递归参数和返回值:参数是传入的整数数组和本层递归的起始位置 stratIndex,无返回值。

  • 递归终止条件:当排列的大小已经等于数组的大小时,将排列插入结果集,并返回。

  • 递归顺序:在本层递归中固定好当前元素后,继续递归进行全排列,在下一层递归中将数组中所有其余的元素遍历一遍。因此我们需要用数组 isUsed 记录哪些元素已经被使用过。

class Solution {
public:
    bool isUsed[10]; // 该数组记录元素是否已经被使用过
    vector<int> path;
    vector<vector<int>> result;
    void findPath(vector<int> &nums,int startIndex){
        if (path.size() == nums.size()){
            result.push_back(path);
            return;
        }
        // 每层都要从 0 开始搜索,因为排列是有序的,[1,2]和[2,1]属于两种不同的排列
        for (int i = 0; i < nums.size(); ++i) {
            if (isUsed[i]){ // 该元素已经在排列中被用过,跳过
                continue;
            }
            path.push_back(nums[i]);
            isUsed[i] = true; // 修改当前元素的使用状态
            findPath(nums,i+1);
            path.pop_back();
            isUsed[i] = false;
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        findPath(nums,0);
        return result;
    }
};

全排列Ⅱ

题干

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

链接:. - 力扣(LeetCode)

思路和代码

本题就是在上一题的思路上进行去重。去重的思路之前说过很多,也就是在当前 for 循环中如果有重复的元素,则跳过。

方法一:用集合 set 去重
class Solution {
public:
    bool isUsed[10];
    vector<int> path;
    vector<vector<int>> result;
    void backTrack(vector<int> &nums){
        if (path.size() == nums.size()){
            result.push_back(path);
            return;
        }
        unordered_set<int> uSet; // 记录当前 for 循环遍历过的元素!!!
        for (int i = 0; i < nums.size(); ++i) {
            if (isUsed[i]) continue;
            if (uSet.find(nums[i]) != uSet.end()) continue; // 去重!!!
            path.push_back(nums[i]);
            isUsed[i] = true;
            uSet.insert(nums[i]);
            backTrack(nums);
            path.pop_back();
            isUsed[i] = false;
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        backTrack(nums);
        return result;
    }
};
方法二:先排序,再用数组去重
class Solution {
public:
    bool isUsed[10];
    vector<int> path;
    vector<vector<int>> result;
    void backTrack(vector<int> &nums){
        if (path.size() == nums.size()){
            result.push_back(path);
            return;
        }
        
        for (int i = 0; i < nums.size(); ++i) {
            if (isUsed[i]) continue;
            if (i > 0 && nums[i] == nums[i-1] && !isUsed[i-1]){ // 对树层去重
                continue; // 去重!!
            }
            path.push_back(nums[i]);
            isUsed[i] = true;
            backTrack(nums);
            path.pop_back();
            isUsed[i] = false;
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        backTrack(nums);
        return result;
    }
};

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

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

相关文章

python动画:manim中的目标位置移动,线条末端和两条线相切的位置处理

一&#xff0c;Manim中目标的位置移动 在 Manim 中&#xff0c;shift 函数用于在三维空间或二维平面上对对象进行平移。通过 shift 方法&#xff0c;用户可以快速移动场景中的物体&#xff0c;指定移动的方向和距离。方向通常由预定义的常量&#xff08;如 UP, DOWN, LEFT, RI…

opencv-python图像增强十五:高级滤镜实现

文章目录 前言二、鲜食滤镜三、巧克力滤镜三&#xff0c;冷艳滤镜&#xff1a; 前言 在之前两个滤镜文章中介绍了六种简单的滤镜实现&#xff0c;它们大多都是由一个单独函数实现的接下来介绍五种结合了之前图像增强文章提的的算法的复合滤镜。本案例中的算法来自于文章一&…

【数学建模】TOPSIS法(优劣解距离法)

TOPSIS法&#xff08;Technique for Order Preference by Similarity to Ideal Solution&#xff0c;优劣解距离法&#xff09;是一种多准则决策分析方法&#xff0c;它基于这样一个概念&#xff1a;最理想的方案应该是距离理想解最近而距离负理想解最远的方案。以下是使用TOPS…

【React原理 - 任务调度和时间分片详解】

概述 在React15的时候&#xff0c;React使用的是从根节点往下递归的方式同步创建虚拟Dom&#xff0c;由于递归具有同步不可中断的特性&#xff0c;所以当执行长任务时(通常以60帧为标准&#xff0c;即16.6ms)就会长时间占用主线程长时间无响应&#xff0c;导致页面卡顿&#x…

如何使用Gitee管理自己的项目

如何使用Gitee管理自己的项目 前言 本地创建的工程项目不利于管理&#xff0c;电脑设备丢失损坏&#xff0c;代码就找不回来了。 并且多人同时使用一个项目工程也不方便。 国内的代码托管平台&#xff0c;Gitee为我实现了远程代码管理。 并且该平台可以设置为开源和私有两种…

公司邮箱如何建立

而建立一套完善的公司邮箱系统&#xff0c;则是实现这一目标的重要一环。本文将深入探讨公司邮箱的建立过程&#xff0c;以及其在业务中的重要性。 1. 确定邮箱域名 公司邮箱的建立首先要确定一个专属的邮箱域名。域名是公司在网络上的身份标识&#xff0c;例如&#xff0c;公…

程序猿成长之路之数据挖掘篇——Kmeans聚类算法

Kmeans 是一种可以将一个数据集按照距离&#xff08;相似度&#xff09;划分成不同类别的算法&#xff0c;它无需借助外部标记&#xff0c;因此也是一种无监督学习算法。 什么是聚类 用官方的话说聚类就是将物理或抽象对象的集合分成由类似的对象组成的多个类的过程。用自己的…

VSCode插件 live Server

普通打开 安装live Server 包含端口 说明内置了服务器

改造小蚁摄像头支持免费无限容量云储存(Samba挂载篇)

为什么要改造&#xff1f; 插卡摄像头最大的一个问题就是频繁的读写会导致内存卡寿命急速下降&#xff0c;哪怕是市面上支持NAS转存的摄像头也是先录制到SD卡里&#xff0c;然后把SD卡上的视频再转存到NAS。同样对内存卡和NAS硬盘寿命都是损耗巨大。而这类监控视频绝大多数情况…

重磅!小米将对外公开超 1000 万行的 Xiaomi Vela 开源代码

点击上方关注 “终端研发部” 设为“星标”&#xff0c;和你一起掌握更多数据库知识 如果说接下来的澎湃OS系统会带来很强的吸引力&#xff0c;那么第二个惊喜也是随之而来&#xff0c;那就是小米Vela开源大动作。 早在2017年起&#xff0c;小米就活跃于 NuttX 社区&#xff0c…

Reinforcement-Learning 2.State Value and Bellman Equation

目录 0.Outline 1.Motivating examples Motivating example 1: Why return is important? Motivating example 2: How to calculate return? 2.State value 3.Bellman equation: Derivation Deriving the Bellman equation An illustrative example Exercise 4.Be…

FreeSWITCH 1.10.10 简单图形化界面28 - 麒麟V10 SP3服务器系统X86和ARM版本安装FreeSWITCH

FreeSWITCH 1.10.10 简单图形化界面28 - 麒麟V10 SP3 服务器系统X86和ARM版本安装FreeSWITCH 界面预览00、先看使用手册01、 麒麟服务器v10 sp3 x86版本1、安装操作系统2、下载安装脚本3、安装 02、麒麟服务器v10 sp3 arm版本1、安装操作系统2、下载安装脚本3、安装 03、登录网…

搭建一个私有的知识库mm-wiki

文章目录 前言一、mm-wiki二、安装步骤下载安装 总结 前言 一般公司内部想要记录一些东西,都需要一个共享文档,当然可以选择类似比较简单易用的,有道云笔记,腾讯文档,语雀等,但是肯定有些公司是保密的,所以不希望这些数据被泄露,当然选择本地存储是最安全的~ 一、mm-wiki 对于…

vue3+vite配置环境变量实现开发、测试、生产的区分

文章目录 一、为什么需要区分 (dev)、测试 (test) 和生产 (prod) 环境二、vue3的项目如何通过配置方式区分不同的环境1、创建不同环境的.env文件2、在不同的.env文件中配置相应的环境变量1&#xff09;.env.develoment2&#xff09;.env.test3&#xff09;.env.production 3、在…

查找2

树表的查找 1&#xff09;二叉排序树 I)二叉排序树的插入 II)二叉排序树的生成 III)二叉排序树的删除 2&#xff09;平衡二叉树 I&#xff09;平衡二叉树调整 、

MMOE+ESSM

MMOE 动机 多个任务之间的相关性并不是很强&#xff0c;这个时候如果再用过去那种共享底座embedding的结构&#xff0c;往往会导致『跷跷板』现象。 当前学术界已经有很多工作意识到1中描述的问题并且尝试去解决&#xff0c;但大多数工作的套路都是『大力出奇迹』的路子&…

zigbee笔记、十五、组播通信原理

一、zigbee四种通讯 1、单播&#xff08;略&#xff09; 2、广播&#xff08;略&#xff09; 3、组播&#xff1a;在zigbee网络中&#xff0c;模块可以用分组来标记&#xff0c;发送的模块如果发送的组号和网络里面标记接收模块的组号相对应&#xff0c;那么这些模块就可以拿到…

深度剖析渗透测试:流程、规范与实战全指南

一、引言 在当今数字化时代&#xff0c;网络安全问题日益凸显。渗透测试作为一种主动的安全评估方法&#xff0c;能够帮助企业和组织发现潜在的安全漏洞&#xff0c;提高系统的安全性。本文将详细介绍渗透测试的实施流程、规范、不同类型的测试方法以及相关的 checklist 和报告…

Matlab处理H5文件

1.读取h5文件 filenamexxx.h5; h5disp(filename) 2.h5文件保存为mat文件 读取 HDF5 文件中的数据 % 指定 HDF5 文件的路径 filename xxx.h5;% 读取 HDF5 文件中的各个数据集 A241_P h5read(filename, /A241_P); A241_W h5read(filename, /A241_W); A242_P h5read(filen…

ensp 中 wlan 的配置过程和示例

一、拓朴&#xff1a; 要求&#xff1a;vlan20 用于笔记本上网&#xff0c;使用Huawei信号&#xff0c;vlan30 用于手机上网&#xff0c;使用 Huawei-5G 信号 二、配置过程&#xff1a; 1、SW1 基本配置&#xff1a; 起 vlan batch 10 20 30&#xff0c;10 为管理 vlan&#…