算法套路二十——单调栈

news2024/12/25 13:32:38

算法套路二十——单调栈

单调栈是一种特殊的数据结构,用于解决与元素的相对大小有关的问题。它是一个栈,但其中的元素以单调递增或单调递减的顺序排列,用于处理与相对大小有关的问题。

算法示例:下一个更大元素

给定一个数组 nums ,返回 nums 中每个元素的 下一个更大元素 。
数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。

单调栈(Monotonic Stack)是一种特殊的数据结构,用于解决一类与寻找下一个更大/更小元素有关的问题。它的特点是栈内的元素保持严格的单调性,可以是递增减。具体步骤如下

  1. 初始化一个空栈。
  2. 遍历数组或列表中的每个元素。
  3. 对于每个元素,执行以下操作:
    • 如果栈为空,则当前元素入栈。
    • 如果当前元素小于等于栈顶元素,当前元素入栈。
    • 如果当前元素大于栈顶元素,则说明当前元素是栈顶元素的下一个更大(更小)元素:
      • 不断地弹出栈顶元素,并记录栈顶元素的下一个更大(更小)元素为当前元素。
      • 将当前元素入栈。
  4. 继续处理步骤3,直到遍历完成。
  5. 如果栈中还有元素,说明它们没有下一个更大(更小)元素,默认为 -1 或者其他特定值。

通过使用单调栈,我们可以在线性扫描中高效地解决这类问题,而不需要套循环。这是因为栈保持了部分信息的记录,我们可以在遍历每个元素时快速找到相关的下一个更大(更小)元素或者距离。

func nextGreaterElement(nums []int) []int {
    n := len(nums)
    ans := make([]int, n)
    stack := []int{}
    for i := n - 1; i >= 0; i-- {
        num := nums[i]  
        // 注意是大于等于
        for len(stack) > 0 && num >= stack[len(stack)-1] {
            stack = stack[:len(stack)-1] // 栈顶元素出栈
        }
        if len(stack) > 0 {
            ans[i] = stack[len(stack)-1]
        } else {
            ans[i] = -1
        }
        stack = append(stack, num)
    }    
    return ans
}

算法练习一:LeetCode503. 下一个更大元素 II

给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。
数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。
在这里插入图片描述

本题可以由于是循环数组,一种方法就是将复制数组拼接在原数组后,但其实可以直接对 i 从2n-1遍历到0且在处理时对下标 i 取模即可,这样遍历到的num:=nums[i%n]即可等价于遍历了拼接数组。其余则与示例完全一样,直接使用单调栈即可。

func nextGreaterElements(nums []int) []int {
    n := len(nums)
    ans := make([]int, n)
    stack := []int{}
    // 从后往前遍历数组的两倍长度
    for i := 2*n - 1; i >= 0; i-- {
        num := nums[i % n]  
        // 注意是大于等于,因为复制了数组,所以出现相等时也需要将栈顶元素出栈
        for len(stack) > 0 && num >= stack[len(stack)-1] {
            stack = stack[:len(stack)-1] // 栈顶元素出栈
        }
        if len(stack) > 0 {
            ans[i%n] = stack[len(stack)-1]
        } else {
            ans[i%n] = -1
        }
        stack = append(stack, num)
    }    
    return ans
}

算法练习:LeetCode1019. 链表中的下一个更大节点

给定一个长度为 n 的链表 head
对于列表中的每个节点,查找下一个 更大节点 的值。也就是说,对于每个节点,找到它旁边的第一个节点的值,这个节点的值 严格大于 它的值。
返回一个整数数组 answer ,其中 answer[i] 是第 i 个节点( 从1开始 )的下一个更大的节点的值。如果第 i 个节点没有下一个更大的节点,设置 answer[i] = 0 。
在这里插入图片描述

func nextLargerNodes(head *ListNode) []int {
    type pair struct{x,i int}
    st:=[]pair{}
    ans:=[]int{}

    for cur:=head;cur!=nil;cur=cur.Next{
        ans=append(ans,0)
        for len(st) > 0 &&cur.Val>st[len(st)-1].x{
            ans[st[len(st)-1].i]=cur.Val
            st=st[:len(st)-1]
        }
        st=append(st,pair{cur.Val,len(ans)-1})

    }
    return ans
}

算法进阶一:LeetCode496. 下一个更大元素 I

nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。
给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。
对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。
返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。
在这里插入图片描述

哈希表+单调栈+倒序遍历

本题有一个难点就是如何找到num1在nums2中的对应位置,因此我们可以改变思路。
由于nums1是nums2的子集且nums2不重复,可以首先构建一个哈希表mp,首先利用底大顶小的单调栈预处理 nums2,倒序遍历nums2(倒序遍历可以不用记录num的下标),来记录num2中每个元素的右侧下一个更大元素,这样我们可以避免每次遍历 nums1 中的元素时都遍历其在nums2中的位置。具体步骤如下

  1. 哈希表 mp记录num2中元素的下一个更大值,单调栈 stack底大顶小,对于每个元素 num,如果 num大于栈顶的元素,那么栈顶的元素就不可能是 num 的下一个更大元素,因此从栈顶开始弹出所有小于 num 的元素,以保持栈中的元素单调递减。只有比栈顶小的元素才能入栈。
  2. 倒序遍历 nums2
    • 弹出栈中所有小于当前元素的元素。
    • 如果栈不为空,则将栈顶元素存入映射表 mp,表示当前元素的右边第一个更大元素。
    • 如果栈为空,则将 -1 存入映射表 mp,表示当前元素没有右边的更大元素。
    • 将当前元素压入栈中。
  3. 遍历 nums1,对于每个元素 num
    • 从映射表 mp 中查找 num 对应的右边第一个更大的元素,并将其存入 res 中。
func nextGreaterElement(nums1, nums2 []int) []int {
    mp := map[int]int{}  // 创建一个空的映射表,用于存储元素和其下一个更大元素的对应关系
    stack := []int{}  // 创建一个空的栈,用于辅助查找下一个更大元素
    for i := len(nums2) - 1; i >= 0; i-- {  // 从nums2的最后一个元素开始遍历
        num := nums2[i]
        for len(stack) > 0 && num >= stack[len(stack)-1] {  // 当栈不为空且当前元素大于等于栈顶元素时
            stack = stack[:len(stack)-1]  // 从栈中弹出栈顶元素,直到栈为空或当前元素小于栈顶元素
        }
        if len(stack) > 0 {
            mp[num] = stack[len(stack)-1]  // 将当前元素所对应的下一个更大元素存入映射表中
        } else {
            mp[num] = -1  // 如果栈为空,则当前元素没有下一个更大元素,将映射表的值设为-1
        }
        stack = append(stack, num)  // 将当前元素压入栈中
    }
    res := make([]int ,len(nums1))  // 创建与nums1相同长度的结果切片
    for i, num := range nums1 {
        res[i] = mp[num]  // 根据映射表找到nums1中每个元素的下一个更大元素并存入结果切片中
    }
    return res  // 返回结果切片
}

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

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

相关文章

C语言指针之 进阶

前言 今天来较为深入的介绍一下指针&#xff0c;希望大家能有所收获&#xff5e; 那么&#xff0c;先进行一些简单的基础知识复习吧。 字符指针 格式&#xff1a;char * 补充&#xff1a; 表达式“abcdef”的值是首字符a的地址 所以当像下面这么使用时&#xff0c;它的含…

2023软件测试岗必问的100个面试题【含答案】

一、测试理论 1.什么是软件测试&#xff1f; 答&#xff1a;软件测试是通过执行预定的步骤和使用指定的数据&#xff0c;以确定软件系统在特定条件下是否满足预期的行为。 2.测试驱动开发&#xff08;TDD&#xff09;是什么&#xff1f; 答&#xff1a;测试驱动开发是一种开…

LeetCode150道面试经典题--最后一个单词的长度(简单)

1.题目 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 2.示例 3.思路 通过对字符串的反转&#xff0c;转为数组开始遍历&#xff0c…

【Git】版本控制器详解之git的概念和基本使用

版本控制器git 初始Gitgit的安装git的基本使用初始化本地仓库配置本地仓库三区协作添加---add修改文件--status|diff版本回退--reset撤销修改删除文件 初始Git 为了能够更⽅便我们管理不同版本的⽂件&#xff0c;便有了版本控制器。所谓的版本控制器&#xff0c;就是⼀个可以记…

二分查找(详解)

目录 介绍 思路 循环实现 详解 递归实现1 详解 注意 递归实现2 两个递归代码之间的区别 总结 介绍 二分查找法&#xff0c;也称为折半查找法&#xff0c;是一种在有序数组中查找特定元素的高效算法。其基本思路是将目标元素与数组中间的元素进行比较&#xff0c…

跳跃游戏 II——力扣45

文章目录 题目描述解法一 贪心题目描述 解法一 贪心 int jump(vector<int>& nums){in

【剑指offer】栈与队列4题 全刷(详解)

目录 目录 目录 [简单]剑指 Offer 09. 用两个栈实现队列 题目 方法 [简单]剑指 Offer 30. 包含min函数的栈 题目 方法1&#xff1a;笨办法 方法2&#xff1a;辅助栈 [困难]剑指 Offer 59 - I. 滑动窗口的最大值 题目 方法&#xff1a;单调队列 [中等]剑指 Offer 5…

固态硬盘对游戏性能的影响及优势解析

固态硬盘的作用在于提高电脑的读取速度&#xff0c;这对于游戏性能的提升有着重要的影响。在一台电脑中&#xff0c;CPU和显卡是核心硬件&#xff0c;而游戏的流畅度则主要取决于显卡的性能&#xff0c;显卡的性能直接影响游戏的帧数高低。如果我们的电脑配置与朋友的电脑相似&…

异常支出的真实成本意想不到!管理采购异常支出有实招

采购中的异常支出是指合同外支出&#xff0c;或在预先制定的采购政策之外从非首选供应商处购买的支出。不同组织中异常支出的差异会很大&#xff0c;异常支出的比例取决于管理下的支出、采购政策实施的成功程度和采购成熟度。 异常支出会给企业带来多少损失&#xff1f; 曾有…

springboot+mybatis实现简单的增、删、查、改

这篇文章主要针对java初学者&#xff0c;详细介绍怎么创建一个基本的springboot项目来对数据库进行crud操作。 目录 第一步&#xff1a;准备数据库 第二步&#xff1a;创建springboot项目 方法1&#xff1a;通过spring官网的spring initilizer创建springboot项目 方法2&am…

qt creater运行按钮灰色,问题记录

第一次安装还没运行就出了三个错误&#xff1a; 1.F:\wei\Qt\Tools\CMake_64\share\cmake-3.24\Modules\CMakeTestCXXCompiler.cmake:62: error: The C compiler "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/BIN/amd64/cl.exe" is not able to compil…

列队 Queue 接口概述

在Java中&#xff0c;Queue&#xff08;队列&#xff09;是一种基本的数据结构&#xff0c;用于按照先进先出&#xff08;FIFO&#xff09;的顺序存储元素。Java提供了多种实现Queue接口的类&#xff0c;以下是几种常见的实现方式&#xff1a; LinkedList&#xff1a;LinkedLis…

linux环形缓冲区kfifo实践4:异步通知fasync

基础知识 异步通知在内核中使用struct fasync_struct数据结构来描述。 <include/linux/fs.h> struct fasync_struct {spinlock_t fa_lock;int magic;int fa_fd;struct fasync_struct *fa_next; /* singly linked list */struct file *fa_file;struct rcu_head fa…

CTF竞赛密码学之 LFSR

概述: 线性反馈移位寄存器&#xff08;LFSR&#xff09;归属于移位寄存器&#xff08;FSR&#xff09;,除此之外还有非线性移位寄存器&#xff08;NFSR&#xff09;。移位寄存器是流密码产生密钥流的一个主要组成部分。 G F ( 2 ) GF(2) GF(2)上一个n级反馈移位寄存器由n个二元…

matlab使用教程(12)—随机数种子和随机数流

1.生成可重复的随机数 1.1指定种子 本示例显示如何通过首先指定种子来重复生成随机数数组。每次使用相同种子初始化生成器时&#xff0c;始终都可以获得相同的结果。首先&#xff0c;初始化随机数生成器&#xff0c;以使本示例中的结果具备可重复性。 rng( default ); 现在…

django实现登录和登录的鉴权

1、创建数据库的管理员表 在models.py 中定义admin表&#xff0c;为了简单&#xff0c;表里只有用户名和密码还有默认加的id 三个字段 from django.db import models# Create your models here.class Admin(models.Model):username models.CharField(verbose_name"用户…

新利好带动 POSE 持续上扬,月内几近翻倍

PoseiSwap 是 Nautilus Chain 上的首个 DEX&#xff0c;得益于 Nautilus Chain 的模块化 Layer3 构架&#xff0c;PoseiSwap 正在基于 zk-Rollup 方案构建全新的应用层&#xff0c;并基于此构建隐私、合规等全新的特性&#xff0c;为未来其布局 RWA 领域推动 Web2、Web3 世界的…

布谷鸟配音:一站式配音软件

这是一款智能语音合成软件&#xff0c;可以快速将文字转换成语音&#xff0c;拥有多种真人模拟发音&#xff0c;可以选择不同男声、女声、童声&#xff0c;以及四川话、粤语等中文方言和外语配音&#xff0c;并且可对语速、语调、节奏、数字读法、多音字、背景音等进行全方位设…

【gridsample】地平线如何支持gridsample算子

文章目录 1. grid_sample算子功能解析1.1 理论介绍1.2 代码分析1.2.1 x,y取值范围[-1,1]1.2.2 x,y取值范围超出[-1,1] 2. 使用grid_sample算子构建一个网络3. 走PTQ进行模型转换与编译 实操以J5 OE1.1.60对应的docker为例 1. grid_sample算子功能解析 该段主要参考&#xff1a;…

最大子数组和——力扣53

文章目录 题目描述解法一 动态规划题目描述 解法一 动态规划 int maxSubArray(vector<int>& nums){int pre=0, res=nums