算法练习第25天|491. 非递减子序列

 491. 非递减子序列

491. 非递减子序列icon-default.png?t=N7T8https://leetcode.cn/problems/non-decreasing-subsequences/

题目描述:

给你一个整数数组 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]]
  • -100 <= nums[i] <= 100

思路分析:

注意,本题不能像算法练习第24天|78.子集、 90.子集II-CSDN博客中的90.子集II那样对元素组进行排序已达到元素子序列去重的目的,可以看上面的示例2,如果我们按照90题那样的做法对原数组进行排列的话【1,2,3,4,4】,就会得出不止一个非递减子序列,这显然与题目输出的【4,4】不符合。所以我们不能对原序列进行排序。

本题给出的示例,还是一个有序数组 [4, 6, 7, 7],这更容易误导大家按照排序的思路去做了。

为了有鲜明的对比,我用[4, 7, 6, 7]这个数组来举例,抽象为树形结构如图:

按照正常的前后顺序进行搜索,会发现两种情况下元素是不能记录的:

(1)如果当前元素比刚刚记录的元素小,那么当前元素就不能往path中添加,因为此时不符合非递减的性质。

(2)同一父节点下的那一层遍历,如果元素之前用过,那么也不能向path中添加。

上面两种情况任意一种发生,path就不能记录当前元素。所以这两种情况对应代码的逻辑关系是或||

下面开始日常的回溯三部曲:

第一步:确认回溯函数的参数与返回值。由于需要在一个集合里面取序列,所以要用到startIndex.

 vector<int> path;
    vector<vector<int>> result;
    void backTracking(vector<int> & nums, int startIndex){}

第二步:确认回溯终止条件。当startIndex达到nums.size()之后就遍历完了,return。

    vector<int> path;
    vector<vector<int>> result;
    void backTracking(vector<int> & nums, int startIndex){  
        if(startIndex == nums.size()){
            return;
        }

第三步:确认单层遍历逻辑。此时就要考虑到我们当前的元素nums[i]是否是上面所述的两种不能记录的情况了。条件(1)如果当前元素比刚刚记录的元素小,用(!path.empty() && nums[i] < path.back())表示;条件(2)同一父节点下该元素(数值)之前用过,用used_numbers[nums[i]+100] == 1表示。

因为题目提示了nums所有元素-100 <= nums[i] <= 100,所以我们使用一个used_numbers数组来记录元素是否用过。由于数组的下标是从0开始算的,所以我们将nums[i]+100,将元素的范围【-100,100】线性拉伸到【0,200】,总共201个数。例如,当前元素为-100时,它存在数组的开始处,当元素为-99时,它存在数组的下标1处,依次类推。使用了该元素,则对应元素置1。另外也可以用set来记录用过的数据。

        int used_numbers[201] = {0};  //记录统一父节点下哪些数字是用过的
        for(int i = startIndex; i < nums.size(); i++){
            if((!path.empty() && nums[i] < path.back())
                || used_numbers[nums[i]+100] == 1)
                continue;
            //不满足if条件则表示该节点可以记录,那么记录当前节点
            path.push_back(nums[i]);
            //判断path长度是否大于等于2,如果是,则reslut记录
            if(path.size() > 1){
                result.push_back(path);
            }
            //-100到100映射到0-201
            used_numbers[nums[i]+100] = 1;  //用过该数字,标志为置1
            //因为子序列最少要有两个元素,所以我们平常的result.push_back(path)就不能直接写了
            //result.push_back(path);
            backTracking(nums, i+1);
            path.pop_back();

        }

整体代码如下:

class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;
    void backTracking(vector<int> & nums, int startIndex){
        
        if(startIndex == nums.size()){
            return ;
        }

        int used_numbers[201] = {0};  //记录统一父节点下哪些数字是用过的
        for(int i = startIndex; i < nums.size(); i++){
            if((!path.empty() && nums[i] < path.back())
                || used_numbers[nums[i]+100] == 1)
                continue;
            //记录当前节点
            path.push_back(nums[i]);
            if(path.size() > 1){
                result.push_back(path);
            }
            //-100到100映射到0-201
            used_numbers[nums[i]+100] = 1;  //用过该数字,标志为置1
            //因为子序列最少要有两个元素,所以我们平常的result.push_back(path)就不能直接写了
            //result.push_back(path);
            backTracking(nums, i+1);
            path.pop_back();
        }
                
    }

    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backTracking(nums, 0);
        return result;
    }
};

下面是使用unordered_set<int>来记录重复元素的写法:

class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;
    void backTracking(vector<int> & nums, int startIndex){
        
        if(startIndex == nums.size()){
            return ;
        }

        unordered_set<int> used_numbers;  //记录统一父节点下哪些数字是用过的
        for(int i = startIndex; i < nums.size(); i++){
            if((!path.empty() && nums[i] < path.back())
                || used_numbers.find(nums[i]) != used_numbers.end())
                continue;
            //记录当前节点
            path.push_back(nums[i]);
            if(path.size() > 1){
                result.push_back(path);
            }
            //-100到100映射到0-201
            used_numbers.insert(nums[i]);  //用过该数字,标志为置1
            //因为子序列最少要有两个元素,所以我们平常的result.push_back(path)就不能直接写了
            //result.push_back(path);
            backTracking(nums, i+1);
            path.pop_back();
        }
                
    }

    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backTracking(nums, 0);
        return result;
    }
};

注意:不管是使用数组还是set来存放使用过的数字,它们都只存在与当前递归层,即下一层的递归中数组和set都会重新创建并初始化,然后for循环在同一层中遍历,这就保证了同一父节点下可以查找元素使用已经用过。

另外,在使用set时,程序运行的时候对unordered_set 频繁的insert,unordered_set需要做哈希映射(也就是把key通过hash function映射为唯一的哈希值)相对费时间,而且每次重新定义set,insert的时候其底层的符号表也要做相应的扩充,也是费事的。使用数组程序还快一些。算法训练第5天|哈希表理论基础 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和-CSDN博客

在上面这篇博文349题中,提到了数组和set作为哈西表时各自的应用场景:

而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费,优先使用set和map。数组,set,map都可以做哈希表,而且数组干的活,map和set都能干,但如果数值范围小的话能用数组尽量用数组

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

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

相关文章

文件IO(三)

文件IO&#xff08;三&#xff09; 左移右移Linux的man 手册文件IO打开文件操作文件关闭文件 caps lock开灯关灯读取按键文件IO操作目录文件打开目录文件操作目录文件 库动态库和静态库的优缺点创建静态库创建动态库 按下右ctrl键 亮灭灯 左移右移 Linux的man 手册 文件IO 打开…

知网AI查重:AI工具如何助力通过检测?

论文降重一直是困扰各界毕业生的“拦路虎”&#xff0c;还不容易熬过修改的苦&#xff0c;又要迎来降重的痛。 其实想要给论文降重达标&#xff0c;我有一些独家秘诀。话不多说直接上干货&#xff01; 1、同义词改写&#xff08;针对整段整句重复&#xff09; 这是最靠谱也是…

旅游门票预订系统小程序源码购票源码

功能介绍&#xff1a; 景点项目 支持发布多个景点项目、景点门票等。 在线支付 支持整合微信支付功能 一款基于ThinkPHP Uniapp开发的旅游i ]票预订系 统 支持景点]票、导游产品便捷预订、美食打卡、景点分 享、旅游笔记分享等综合系统,提供前后台无加密源码&#xff0c;支…

JS脚本打包成一个 Chrome 扩展(CRX 插件)

受这篇博客 如何把CSDN的文章导出为PDF_csdn文章怎么导出-CSDN博客 启发&#xff0c;将 JavaScript 代码打包成一个 Chrome 扩展&#xff08;CRX 插件&#xff09;。 步骤&#xff1a; 1.创建必要的文件结构和文件&#xff1a; manifest.jsonbackground.jscontent.js 2.编写…

汇编:调用Win32 API

在32位汇编程序中使用 Win32 API 是很常见的&#xff0c;特别是在开发 Windows 应用程序时调用的频率很高&#xff0c;Win32 API 提供了访问 Windows 操作系统功能的接口&#xff0c;包括窗口、消息处理、文件操作、网络通信等等。以下是使用 Win32 API 的一般步骤&#xff1a;…

Controller类明明写了@CrossOrigin跨域注解,但还是有跨域问题

可能是写的过滤器干扰到了跨域处理。如&#xff1a; 此时&#xff0c;先注释掉过滤器注解&#xff0c;让其不生效&#xff0c;就可以避免干扰跨域处理了 不过&#xff0c;这只能暂时解决该问题&#xff0c;毕竟过滤器还是要用的&#xff0c;后续我再探索一下。。。。。。。

springboot实现文件上传功能,整合云服务

文章目录 这是springboot案例的,文件上传功能的拆分,本篇将带大家彻底了解文件上传功能,先从本地存储再到云存储,全网最详细版本,保证可以学会,可以了解文件上传功能的开发文件上传功能剖析进行书写一个小的文件上传文件上传的文件三要素首先表单提交的方式要是 post方式,第二个…

艾体宝洞察 | Redis Enterprise对比ElastiCache

选择缓存数据库时&#xff0c;如何在Amazon ElastiCache和Redis Enterprise之间做出选择&#xff0c;应当考虑哪些标准&#xff1f; ElastiCache 通常可以满足基本的缓存需求&#xff0c;因此是一种适合初始阶段的解决方案。但随着使用量的增加&#xff0c;ElastiCache很快会变…

FreeSWITCH 1.10.10 简单图形化界面21-录音相关

FreeSWITCH 1.10.10 简单图形化界面21-录音相关 FreeSWITCH GUI界面预览00、安装FreeSWITCH GUI先看使用手册1、录音相关的应用11、record用法&#xff1a;举例&#xff1a;注意&#xff1a; 12、record_session用法&#xff1a;举例&#xff1a; 2、录音相关的变量3、单腿录音…

ICPC训练赛补题集

ICPC训练赛补题集 文章目录 ICPC训练赛补题集D - Fast and Fat (负重越野)I-路径规划G. Inscryption(邪恶铭刻)NEW Houses雪中楼(西安交通大学)L.BracketGenerationE - Checksum D - Fast and Fat (负重越野) 原题链接&#xff1a;原题链接 题意&#xff1a;体重大的背体重小的…

图像处理ASIC设计方法 笔记26 非均匀性校正SOC如何设计

在红外成像技术领域,非均匀性校正是一个至关重要的环节,它直接影响到成像系统的性能和目标检测识别的准确性。非均匀性是指红外焦平面阵列(IRFPA)中各个像元对同一辐射强度的响应不一致的现象,这种不一致性可能是由于制造过程中的缺陷、材料的不均匀性或者像元间的热电特性…

Mysql 8.0.37 安装教程

图片有点长&#xff0c;慢慢来 安装教程 安装地址&#xff1a;MySQL :: MySQL Downloads 进入官网 下载社区版 此处有两个版本&#xff0c;我们下载的是8.0.37版本 第一个需要联网安装&#xff0c;我们现在第二个离线安装 server only&#xff1a;仅安装MySQL server clien…

SpringCloud如何实现SSO单点登录?

目录 一、SpringCloud框架介绍 二、什么是SSO单点登录 三、单点登录的必要性 四、SpringCloud如何实现SSO单点登录 一、SpringCloud框架介绍 Spring Cloud是一个基于Spring Boot的微服务架构开发工具集&#xff0c;它整合了多种微服务解决方案&#xff0c;如服务发现、配置…

Django里多app

在 Django 里的某一个项目&#xff0c;里面得包含很多 App (功能)&#xff0c;那么如何在该项目里管理这么多App呢&#xff1f; 先说明下背景&#xff1a;未先创建 apps 文件夹来存各个app文件夹&#xff0c;直接在项目文件目录里创建各个app。为了便于管理&#xff0c;得将各…

【TB作品】msp430f5529单片机墨水屏,口袋板,显示温度和万年历,tmp421温度,RTC时间

文章目录 一、部分程序二、展示三、全部代码下载 一、部分程序 int main(void) {WDTCTL WDTPW | WDTHOLD; //关闭看门狗init(); //屏幕初始化InitIIC(); //I2C初始化TMP_Init(); //tmp421初始化SetupRTC();_EINT();while (1){} }#pragma vectorRT…

在鸿蒙中身份校验的手势密码的实现

在harmony中它提供了默认的组件PatternLock()&#xff1b; 这个就能直接显示九宫格密码验证 并且他有两个主要的回调事件 .onDotConnect密码输入选中宫格圆点时触发该回调 .onPatternComplete&#xff1a;密码输入结束时触发该回调 //如代码实现 PatternLock().sideLength(32…

【scikit-learn009】异常检测系列:单类支持向量机(OC-SVM)实战总结(看这篇就够了,已更新)

1.一直以来想写下机器学习训练AI算法的系列文章,作为较火的机器学习框架,也是日常项目开发中常用的一款工具,最近刚好挤时间梳理、总结下这块儿的知识体系。 2.熟悉、梳理、总结下scikit-learn框架OCSVM模型相关知识体系。 3.欢迎批评指正,欢迎互三,跪谢一键三连! 4.欢迎…

linux上VirtualBox使用

前言 最近想把唯一的windows系统装成linux&#xff0c; 但是确实存在一些特殊软件无法舍弃&#xff0c;所有装完linux需要用虚拟机装个windows 上来使用特定的一些软件&#xff08;不想用wine了&#xff09;。 还有对一些特定usb设备的透传&#xff0c;这样才能保证在虚拟机中…

计算机组成原理·存储系统疑点归纳

组原这门课有点学得不是很懂&#xff0c;现在快考试了&#xff0c;挑几个做错了的题分析、记录一下。 N o . 1 \mathit{No}.1 No.1  x x x、 y y y 为定点整数&#xff0c;其格式为 1 1 1 位符号位、 n n n 位数值位&#xff0c;若采用补码一位乘法实现乘法运算&#xff0c;则…

idea中导入代码文件无法修改,显示File is read-only,怎么办?难办?那就别办了------看下面

File is read-only 文件属性只读&#xff0c;不可修改。。。。。 第一次遇到这种问题&#xff0c;去网上搜了一堆方法&#xff0c;都试了&#xff0c;没用&#xff0c;最后居然还建议我重装idea&#xff0c;我还差点信了&#xff0c;经9X9难后&#xff0c;取得真经。 问题解决…