单调栈题目总结

news2025/1/22 8:52:43

单调栈

496. 下一个更大元素 I

503. 下一个更大元素 II

739. 每日温度

6227. 下一个更大元素 IV

模版归纳

「单调栈」顾名思义就是具有单调性的栈结构,一般常用于找到下一个更大的元素,即当前元素右侧第一个更大的元素

看下面一个例子:2 1 2 4 3
在这里插入图片描述

我们只看得到比我们更高的元素,所以比我们矮的元素就无关紧要

下面给出「单调栈」的模版:

int[] nextGreaterElement(int[] nums) {
    int n = nums.length;
    // 存放答案的数组
    int[] res = new int[n];
    Stack<Integer> s = new Stack<>(); 
    // 倒着往栈里放
    for (int i = n - 1; i >= 0; i--) {
        // 判定个子高矮
        while (!s.isEmpty() && s.peek() <= nums[i]) {
            // 矮个起开,反正也被挡着了
            s.pop();
        }
        // nums[i] 身后的更大元素
        res[i] = s.isEmpty() ? -1 : s.peek();
        s.push(nums[i]);
    }
    return res;
}

现在给几个变形

如果我们现在需要找到下一个大于等于的元素,怎么办?很简单只需要修改一个地方即可:

// 注意:我们把 s.peek() == nums[i] 的元素留下了
while (!s.isEmpty() && s.peek() < nums[i]) {
    // 矮个起开,反正也被挡着了
    s.pop();
}

如果我们现在需要找到下一个更小的元素,怎么办?很简单只需要修改一个地方即可:

while (!s.isEmpty() && s.peek() >= nums[i]) {
    // 高个起开,太碍眼了
    s.pop();
}

如果我们现在需要找到上一个更大的元素,怎么办?很简单只需要变换一下遍历顺序即可:

// 正着往栈里放
for (int i = 0; i < n; i++) {
    // 其他逻辑不变
}

题目实战

上面给出了「单调栈」的模版以及几种不同的变形,下面来几道题目练练手!!

下一个更大元素 I

题目详情可见 下一个更大元素 I

这个题目基本上就是一个模版题,处理上用到了一个小技巧

由于nums1nums2的子集,所以我们先求出nums2的所有下一个更大元素,用Map映射保存一下即可

public int[] nextGreaterElement(int[] nums1, int[] nums2) {
    Map<Integer, Integer> greaterMap = new HashMap<>();
    Stack<Integer> stack = new Stack<>();
    for (int i = nums2.length - 1; i >= 0; i--) {
        while (!stack.isEmpty() && stack.peek() <= nums2[i]) stack.pop();
        // 保存 nums2[i] 下一个更大元素
        greaterMap.put(nums2[i], stack.isEmpty() ? -1 : stack.peek());
        stack.push(nums2[i]);
    }
    int[] res = new int[nums1.length];
    // 寻找 nums1 中元素在 nums2 中的下一个更大元素
    for (int i = 0; i < nums1.length; i++) {
        res[i] = greaterMap.get(nums1[i]);
    }
    return res;
}
下一个更大元素 II

题目详情可见 下一个更大元素 II

这个问题加入了一个循环数组的概念,我们处理的方法就是利用 2 倍的数组即可

为了节约空间,我们可以利用「模运算」实现 2 倍数组的效果,而不需要单独开辟空间

public int[] nextGreaterElements(int[] nums) {
    int n = nums.length;
    int[] res = new int[n];
    Stack<Integer> stack = new Stack<>();
    for (int i = 2 * n - 1; i >= 0; i--) {
        while (!stack.isEmpty() && stack.peek() <= nums[i % n]) stack.pop();
        res[i % n] = stack.isEmpty() ? -1 : stack.peek();
        stack.push(nums[i % n]);
    }
    return res;
}
每日温度

题目详情可见 每日温度

这个问题需要让我们求与下一个更大元素的间隔,所以我们稍微转变一下栈中存储的内容即可

模版中存储的内容为num[i],这样就损失了下一个更大元素的位置信息。如果我们改为存储「下标」,既保留了位置信息,也可以通过下标获得值

public int[] dailyTemperatures(int[] temperatures) {
    int[] res = new int[temperatures.length];
    Stack<Integer> stack = new Stack<>();
    for (int i = temperatures.length - 1; i >= 0; i--) {
        while (!stack.isEmpty() && temperatures[stack.peek()] <= temperatures[i]) stack.pop();
        res[i] = stack.isEmpty() ? 0 : stack.peek() - i;
        stack.push(i);
    }
    return res;
}
下一个更大元素 IV

题目详情可见 下一个更大元素 IV

这个题目更形象的名字应该是:下下个更大的元素

public int[] secondGreaterElement(int[] nums) {
    int n = nums.length;
    int[] ans = new int[n];
    Arrays.fill(ans, -1);
    // s1 用来存储还没有遇到「比它大的下一个元素」的元素
    Deque<Integer> s1 = new ArrayDeque<>();
    // s2 用来存储遇到一个「比它大的下一个元素」的元素
    Deque<Integer> s2 = new ArrayDeque<>();
    for (int i = 0; i < nums.length; i++) {
        // 如果 s2 中有比 nums[i] 小的元素,说明 nums[i] 就是该元素的下下个更大的元素
        while (!s2.isEmpty() && nums[i] > nums[s2.peek()]) ans[s2.poll()] = nums[i];
        Deque<Integer> t = new ArrayDeque<>();
        // 如果 s1 中有比 nums[i] 小的元素,说明该元素遇到了一个「比它大的下一个元素」的元素,移到 s2 中
        // 注意:需要按顺序移动!!比如在 s1 中的顺序是 a1 a2 a3,那么移到 s2 中的存储顺序也应该 a1 a2 a3
        // 所以这里借助另外一个栈来中转一下,不然顺序会反转
        while (!s1.isEmpty() && nums[i] > nums[s1.peek()]) t.push(s1.poll());
        s1.push(i);
        while (!t.isEmpty()) s2.push(t.poll());
    }
    return ans;
}

其实除了用两个栈,还可以用两个堆来实现,堆比栈更好理解,但是原理都是一样的!

public int[] secondGreaterElement(int[] nums) {
    int n = nums.length;
    int[] ans = new int[n];
    Arrays.fill(ans, -1);
    // 小根堆
    Queue<Integer> q1 = new PriorityQueue<>((a, b) -> nums[a] - nums[b]);
    Queue<Integer> q2 = new PriorityQueue<>((a, b) -> nums[a] - nums[b]);
    for (int i = 0; i < n; i++) {
        int x = nums[i];
        while (!q2.isEmpty() && nums[q2.peek()] < x) ans[q2.poll()] = x;
        while (!q1.isEmpty() && nums[q1.peek()] < x) q2.offer(q1.poll());
        q1.offer(i); 
    }
    return ans;
}

引用

  • https://lfool.github.io/LFool-Notes/algorithm/%E5%8D%95%E8%B0%83%E6%A0%88.html

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

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

相关文章

【C++学习手札】多态:掌握面向对象编程的动态绑定与继承机制(初识)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;世界上的另一个我 1:02━━━━━━️&#x1f49f;──────── 3:58 &#x1f504; ◀️ ⏸ ▶️ ☰ &am…

应用回归分析:岭回归

岭回归&#xff0c;也称为Tikhonov正则化&#xff0c;是一种专门用于处理多重共线性问题的回归分析技术。多重共线性是指模型中的自变量高度相关&#xff0c;这种高度的相关性会导致普通最小二乘法&#xff08;OLS&#xff09;估计的回归系数变得非常不稳定&#xff0c;甚至无法…

CDN缓存有什么作用?

CDN缓存是内容分发网络的核心技术之一&#xff0c;它的作用在于通过将内容缓存在边缘服务器上&#xff0c;提高内容的访问速度和可用性。以下是CDN缓存的几个主要作用&#xff1a; 加速内容的访问速度 CDN缓存通过将内容缓存在距离用户更近的边缘服务器上&#xff0c;减少了内…

【C++】C++入门—初识构造函数 , 析构函数,拷贝构造函数,赋值运算符重载

C入门 六个默认成员函数1 构造函数语法特性 2 析构函数语法特性 3 拷贝构造函数特性 4 赋值运算符重载运算符重载赋值运算符重载特例&#xff1a;前置 与 后置前置&#xff1a;返回1之后的结果后置&#xff1a; Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&…

基于SSM的电影购票系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的电影购票系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

这才是大学生该做的副业,别再痴迷于游戏了!

感谢大家一直以来的支持和关注&#xff0c;尤其是在我的上一个公众号被关闭后&#xff0c;仍然选择跟随我的老粉丝们&#xff0c;你们的支持是我继续前行的动力。为了回馈大家长期以来的陪伴&#xff0c;我决定分享一些实用的干货&#xff0c;这些都是我亲身实践并且取得成功的…

【蓝桥杯】算法模板题(Floyd算法)

一.弗洛伊德算法 用途&#xff1a;用来求解多源点最短路径问题。 思想&#xff1a;Floyd算法又称为插点法&#xff0c;是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法。 主要步骤&#xff1a; 1&#xff09;初始化&#xff1a;使用邻接矩阵初始化dis…

离线数仓(三)【业务日志采集平台搭建】

前言 上一篇我们搭建完了用户行为日志数据的采集平台&#xff0c;其实也就是用两个 flume 采集数据到Kafka 中&#xff08;这种结构只有 source 和 channel 没有 sink&#xff09; 。离线数仓中的数据除了用户日志&#xff0c;还有就是业务数据了。 1、电商业务简介 1.1 电商…

Android电量相关知识

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、 查看耗电情况3.1 注册广播 ACTION…

数据结构——lesson3单链表介绍及实现

目录 1.什么是链表&#xff1f; 2.链表的分类 &#xff08;1&#xff09;无头单向非循环链表&#xff1a; &#xff08;2&#xff09;带头双向循环链表&#xff1a; 3.单链表的实现 &#xff08;1&#xff09;单链表的定义 &#xff08;2&#xff09;动态创建节点 &#…

【C++初阶】新手值得一做vector的oj题

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

SQL补充:窗口函数

SQL窗口函数 结合order by关键词和limit关键词是可以解决很多的topN问题&#xff0c;比如从二手房数据集中查询出某个地区的最贵的10套房&#xff0c;从电商交易数据集中查询出实付金额最高的5笔交易&#xff0c;从学员信息表中查询出年龄最小的3个学员等。 但是&#xff0c;…

端口号被占用怎么解决

1、快捷键"winR"打开运行&#xff0c;在其中输入"cmd"命令&#xff0c;回车键打开命令提示符。 2、进入窗口后&#xff0c;输入"netstat -ano"命令&#xff0c;可以用来查看所有窗口被占用的情况。 比如端口号为7680的端口被占用了&#xff0c…

Java+Swing+Txt实现通讯录管理系统

目录 一、系统介绍 1.开发环境 2.技术选型 3.功能模块 4.系统功能 1.系统登录 2.查看联系人 3.新增联系人 4.修改联系人 5.删除联系人 5.工程结构 二、系统展示 1.登录页面 2.主页面 3.查看联系人 4.新增联系人 5.修改联系人 三、部分代码 Login FileUtils …

c高级 函数+Makefile

一、作业 1.写一个函数&#xff0c;输出当前用户的uid和gid&#xff0c;并使用变量接收结果 #!/bin/bash function fun(){retid -uret1id -gecho $ret $ret1 } retfun echo $ret二、练习回顾 1.分文件编译&#xff08;实现冒泡排序&#xff09; 正确的&#xff1a;将数组的…

day32打卡

day32打卡 122. 买卖股票的最佳时机 II 解法&#xff0c;贪心&#xff1a;局部&#xff0c;收集每天的正利润-》整体&#xff0c;获取最大利润 从第0天到第3天&#xff0c;利润为&#xff1a;price[3] - price[0]&#xff0c;也可以是(price[3] - price[2]) (price[2] - pr…

UI设计20问(01):如何规避公说公有理婆说婆有理。

hello&#xff0c;我是大千UI工场&#xff0c;这次又开辟了一个新专题&#xff0c;回答UI设计中经常碰到问题&#xff0c;本期先回答UI设计评判标准的问题&#xff0c;欢迎关注评论点赞转发。 一、什么是公说公有理婆说婆有理 "公说公有理&#xff0c;婆说婆有理"是…

EasyUI动态加载组件

要实现如下的效果&#xff0c;在表格中显示进度条 主要是需要再次初始化组件&#xff0c;借用ChatGPT的意思是&#xff1a; 在许多 JavaScript UI 框架中&#xff0c;包括 EasyUI&#xff0c;在动态地创建或插入新的 DOM 元素后&#xff0c;通常需要手动初始化相关的组件或特性…

阿里云香港轻量应用服务器是什么线路?

阿里云香港轻量应用服务器是什么线路&#xff1f;不是cn2。 阿里云香港轻量服务器是cn2吗&#xff1f;香港轻量服务器不是cn2。阿腾云atengyun.com正好有一台阿里云轻量应用服务器&#xff0c;通过mtr traceroute测试了一下&#xff0c;最后一跳是202.97开头的ip&#xff0c;1…

【Qt学习】QIcon类 + 利用qrc机制设置图片路径(QtCreator)

文章目录 1. QIcon / windowIcon2. setIcon() 与 setwindowIcon()2.1 setIcon() 介绍与使用2.2 setWindowIcon 介绍与使用 3. 路径问题 & qrc机制的引入3.1 绝对路径 / 相对路径 的问题3.2 qrc机制3.3 在QtCreator下利用qrc机制引入图片 1. QIcon / windowIcon QIcon QIco…