【算法练习Day24】递增子序列全排列全排列 II

news2024/11/18 15:40:41

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:练题
🎯长路漫漫浩浩,万事皆有期待

文章目录

  • 递增子序列
    • 容易出错的地方
  • 全排列
  • 全排列 II
  • 总结:

递增子序列

491. 递增子序列 - 力扣(LeetCode)
在这里插入图片描述

递增子序列也是一道求子集的问题,但是这道题与子集II的不同之处是,这道题不能够对数组排序,而且要求求出答案序列为2以上的递增子序列。

不能排序求递增子序列是有点难度的,需要一些技巧,首先给定数组nums可能含有重复数据,而做过往期的朋友都知道,去重是一定要排序的,那么不排序我们怎么做呢?

思路是这样的,在函数实现的内部,我们定义一个哈希表,该哈希表存储的是当前数层中我们取过那些数据,取过的我们标记一下,这里用数组还是其他什么做哈希都可以,但是数组更高效。

代码如下:

class Solution {
public:
        vector<vector<int>> result;
        vector<int> path;
        void backtracking(vector<int>&nums,int startIndex)
        {
            if(path.size()>1)
            {
                result.push_back(path);
            }
            unordered_set<int> uset;
            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();
            }
        }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        result.clear();
        path.clear();
        backtracking(nums,0);
        return result;
    }
};

没有接触过不能排序而去重的逻辑,有时候还真的想不出来这种解法,因为它是在递归函数内部中间创建的哈希表,我们并不需要对它进行回溯,原因是每进入下一层递归,也就是增加了递归深度它会新建一个哈希,来保存当前树层所插入过的节点,换句话说它保存的是树的横向结构。我们在for循环中,通过判断该层的哈希里要插入的数据有没有插进去过,即可完成数层去重。而控制递增子序列就显得格外简单了,我们仅仅是比较一下当前我们要插入的合法数据和要插入的数组的最后一个数据谁大就可以了,如果要插入的大直接插入,不行的话还是continue,理由还是相同的,continue是为了能让i往后走,找之后的数据看看能不能接着插入进数组。

容易出错的地方

由于我们是根据题目给定数组nums对应的个数据做的哈希,为了判断这个数是否在该树层用过。当我们用数组做哈希结构,要注意测试用例的数据范围,数据包含负数,且是-100-100的数据,所以我们用201个空间并且使数据主动加上100,来避免对负数下标的访问,这是有讲究的定义数组,而非随便取数组大小。当然选用set或者map可以避免这方面的判断,但是当数据范围不大时候,选用数组做哈希可以提高运行效率。

全排列

46. 全排列 - 力扣(LeetCode)
在这里插入图片描述

终于进到了回溯算法的下一个主题,全排列,到了排列部分也就意味着我们的回溯算法例题,快要进入尾声了。排列和组合的模板不同。换句话说,组合问题,子集问题,切割问题三种问题实际上都可以类比为组合问题的大类里面,因为无论是子集问题还是切割问题,都是不能向前去取数

但是排列可以,{1,2}和{2,1}是完全不同的排列,这就意味着我们在写递归时要考虑到这一点,如何即清楚我们下一层从哪里开始,又要可以遍历到这个数之前的数据呢?答案是用到一个数组来保存,这个数组标识着我们哪些数已经取过了,哪些数没有取,也就是说排列问题(往回取数的问题)无论是否涉及到去重都要加入一个标记数组。

先看代码分析

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;
            }
            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;
    }
};

用标记数组是如何实现的呢?在取数之后做标记,往深层递归时,由于被取过的数仍然被标记着,我们可以让i=0每次让它从第一个数开始找,碰到没有被标记的我们直接加入path中,那么是如何像示例中一样,由{1,2,3}逐渐转变为{2,1,3}的呢?实际上也是由于回溯,回溯删除1之后,此时i=0上去i++变为1,这个时候取到的是nums[1]也就是2了,递归问题的取数有时候会突然想不明白,可以自己用编译器调试一下看看,递归是如何进行的,回溯又是如何回溯的,多调试才有利于对递归更深的了解。

全排列 II

47. 全排列 II - 力扣(LeetCode)
在这里插入图片描述

知道了全排列的做法,那么全排列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;
    }
};

看到这个代码可能有同学会产生疑惑,我们这里还用used[i]来判断,那出现数组相同数据时候例如{1,1,2}会不会第二个1进不去啊,这里大可不必担心,因为我们判断的是used[i]也就是标记数组的位置,是第一个位置还是第二个位置是否为1的判断,与你本身数值是什么没有任何关系,这一点一定要注意。

总结:

今天我们完成了递增子序列、全排列、全排列 II三道题,相关的思想需要多复习回顾。接下来,我们继续进行算法练习。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

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

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

相关文章

微信手续费2023标准

不管是微信还是支付宝&#xff0c;商户最低的收款手续费率可以达到0.2%费率。一般我们普通商户的收款费率一般在0.6左右&#xff0c;当然也有使用0.3的&#xff0c;也就是1万元的费率是30-60块钱&#xff0c;对于一些流水比较大的商家来说&#xff0c;确实很有必要把这个手续费…

【实用技巧】Latex写算法伪代码(格式篇)

本文主要介绍个人在编写Latex算法伪代码时所遇到的格式问题。 目录 包冲突换行与缩进算法换页 包冲突 \usepackage{algorithm} \usepackage{algorithmic} \usepackage{algorithmicx} \usepackage{algpseudocode} 网上查找算法伪代码第三方包&#xff0c;主要会跳出来这四…

虹科案例 | 瑞士Agroscope研究所利用压力传感器自动测量反刍动物(奶牛)的咀嚼运动

——用于动物测量研究的数据记录仪&#xff1a;虹科MSR145 瑞士Agroscope研究所隶属于联邦农业办公室&#xff0c;是农业、食品和环境领域可持续发展的推动力量&#xff0c;为农业和环境政策决策以及法规执行提供科学和技术基础。 作为Agroscope研究所的合作代表&…

【超详细】CentOS 7安装MySQL 5.7【安装及密码配置、字符集配置、远程连接配置】

准备工作&#xff1a;CentOS 7系统&#xff0c;并确保可以联通网络 1、获取MySQL 5.7 Community Repository软件包 注意&#xff1a;这里使用的是root用户身份。 wget https://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm2、安装软件包 rpm -ivh mysql5…

PyTorch入门教学——TensorBoard使用

1、TensorBoard简介 TensorBoard是Google开发的一个机器学习可视化工具。其主要用于记录机器学习过程&#xff0c;例如&#xff1a; 记录损失变化、准确率变化等记录图片变化、语音变化、文本变化等。例如在做GAN时&#xff0c;可以过一段时间记录一张生成的图片绘制模型 2、…

数字秒表VHDL启动暂停清零,源码和视频

名称&#xff1a;数字秒表VHDL启动暂停清零&#xff08;代码在文末付费下载&#xff09; 软件&#xff1a;Quartus 语言&#xff1a;VHDL 代码功能&#xff1a; 数字秒表 使用VHDL语言设置数字秒表。要求具有百分秒、秒和分钟显示,百分秒范围00-99,秒范围00-59,分钟范围0…

《java 桌面软件开发》swing 以鼠标为中心放大缩小移动图片

swing 使用Graphic2D 绘制图片&#xff0c;要实现对图片进行缩放和自由拖动。 1.以鼠标所在的位置为中心&#xff0c;滚轮控制缩放 2.缩放后再支持鼠标拖动。 基本原理&#xff1a; 利用scale() 函数。进行缩放。但是要注意的地方是&#xff0c;如果是在 public void paintCom…

Linux 下安装配置部署MySql8.0

一 . 准备工作 MySQL安装包&#xff1a;在官网下载需要的版本&#xff0c;这里我用的版本是 MySQL 8.0.34 https://dev.mysql.com/downloads/mysql/ 本次linux机器使用的是阿里云ECS实例 二 . 开始部署 1. 将安装包上传至服务器 解压到当前文件夹 tar -zxvf mysql-8.0.34…

Python 实现http server接收mutipart/form-data文件 方法1

Python 实现http server接收mutipart/form-data文件 方法1 1 Server端代码2 客户端截图3 代码说明 1 Server端代码 import os from flask import Flask, request from werkzeug.utils import secure_filenameapp Flask(__name__) app.config[UPLOAD_FOLDER] E://recv//app.ro…

玩游戏缺失“d3d11.dll丢失“的问题的五种解决方案

在我日常的计算机维护工作中&#xff0c;经常遇到一些用户报告他们遇到了"d3d11.dll丢失"的问题。这是一个常见的Windows系统错误&#xff0c;通常会导致程序无法正常运行。在这篇文章中&#xff0c;我将分享我找到的五种有效的解决方法&#xff0c;以帮助这些用户解…

开源的容器运行时项目 Podman

本心、输入输出、结果 文章目录 开源的容器运行时项目 Podman前言Podman 简介Podman 与 Docker 的区别Podman 在使用上和 Docker 有什么区别从构建者角度分析 Podman 在使用上和 Docker 有什么区别从使用者角度分析 Podman 在使用上和 Docker 有什么区别 Podman 常用命令容器镜…

Linux shell编程学习笔记14:编写和运行第一个shell脚本hello world!

* 20231020 写这篇博文断断续续花了好几天&#xff0c;为了说明不同shell在执行同一脚本文件时的差别&#xff0c;我分别在csdn提供线上Linux环境 &#xff08;使用的shell是zsh&#xff09;和自己的电脑上&#xff08;使用的shell是bash&#xff09;做测试。功夫不负有心人&am…

详解如何利用Pytest Cache Fixture实现测试结果缓存

这篇文章主要为大家详细介绍了如何利用Pytest Cache Fixture实现测试结果缓存,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下− 前言 接口自动关过程中&#xff0c;经常会遇到这样一些场景&#xff0c;“请求2需要用到请求1响应的数据”&#xff0c;常见的…

人脸识别顶会论文及源码合集,含2023最新

今天和大家聊聊人脸识别。 人脸识别的技术经过不断发展已经相当成熟&#xff0c;在门禁、监控、手机解锁、移动支付等实际场景都能看到。我们比较熟悉的识别方式是基于可见光图像的人脸识别&#xff0c;这种方式有个非常明显的缺点&#xff1a;光线限制。 在近两年的人脸识别…

如何解决NSIS 2G文件的限制

Internal compiler error #12345: error mmapping datablock to 33556079.Note: you may have one or two (large) stale temporary file(s) left in your temporary directory (Generally this only happens on Windows 9x). 最近在使用NSIS打包一个7.3GB的可执行程序时&…

【算法|动态规划No.25】leetcode LCR 020. 回文子串

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

Spring学习笔记注解式开发(3)

Spring学习笔记&#xff08;3&#xff09; 一、Bean的注解式开发1.1、注解开发的基本和Component1.2 注解式开发8.3、Component的三个衍生注解 二、Bean依赖注入注解开发2.1、依赖注入相关注解2.2、Autowired扩展 三、非自定义Bean注解开发四、Bean配置类的注解开发五、Spring注…

编译安装Nginx+GeoIP2自动更新+防盗链+防爬虫+限制访问速度+限制连接数

此文章是Nginx的GeoIP2模块和MaxMind国家IP库相互结合&#xff0c;达到客户端IP访问的一个数据记录以及分析&#xff0c;同时还针对一些业务需求做出对Nginx中间件的控制&#xff0c;如&#xff1a;防盗链、防爬虫、限制访问速度、限制连接数等 该篇文章是从一个热爱搞技术的博…

TSINGSEE智慧加油站可视化监管与风险预警方案

一、方案背景 加油站属于危化品行业&#xff0c;如何在日常加油卸油作业过程中保障人员、财产安全是重中之重。国内加油站日常管理主要依靠人为管控、监控摄像头监督及人工巡检等方式&#xff0c;管控手段存在低效性和滞后性&#xff0c;迫切需要将人工智能、物联网、大数据等…

07-React-redux和redux的使用

07.react-redux和redux的使用 1.redux的使用 1).redux的理解 a.redux是什么 redux是一个专门用于做状态管理的JS库(不是react插件库)。它可以用在react, angular, vue等项目中, 但基本与react配合使用。作用: 集中式管理react应用中多个组件共享的状态。 b.什么情况下需要使…