【栈】单调栈详情介绍及其运用

news2024/12/23 19:10:22

单调栈

  • 单调栈的概述(Overview)
    • 何时使用单调栈
    • 模拟单调递增栈
  • 单调栈的运用(算法练习题)
    • 模板
    • 【练习一、单调栈】739. 每日温度
    • 【练习二、单调栈+哈希表】496. 下一个更大元素 I
    • 【练习三、单调栈+循环数组】503. 下一个更大元素 II
    • 【练习四、单调栈】👍42.接雨水
    • 【练习五、单调栈】👍84. 柱状图中最大的矩形

单调栈我是跟着代码随想录刷题的时候看见的,觉得挺有趣的、也挺好用的,然后就来CSDN找博客学习了。代码随想录是用C++去解决算法问题,我也喜欢用C++去刷题,这里题解等用的是Java。借用了这篇《单调栈》博客以及代码随想录推荐的题!!!

单调栈的概述(Overview)

单调栈是指栈内元素是单调的,固分为单调递增栈/单调递减栈

  • 单调递增栈:栈内元素递增,是由低向顶的。
  • 单调递减栈:与上相反。

何时使用单调栈

通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。

模拟单调递增栈

单调栈内部是一般情况放索引的,结合实际的一维数组,对右边或左边首个大或小的元素的索引进行保存和分析。

现在有一组数10,3,7,4,12。从左到右依次入栈,则如果栈为空或入栈元素值小于栈顶元素值,则入栈;否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素小的元素全部出栈。单调递减的栈反之。

  • 10入栈时,栈为空,直接入栈,栈内元素为10。

  • 3入栈时,栈顶元素10比3大,则入栈,栈内元素为10,3。

  • 7入栈时,栈顶元素3比7小,则栈顶元素出栈,此时栈顶元素为10,比7大,则7入栈,栈内元素为10,7。

  • 4入栈时,栈顶元素7比4大,则入栈,栈内元素为10,7,4。

  • 12入栈时,栈顶元素4比12小,4出栈,此时栈顶元素为7,仍比12小,栈顶元素7继续出栈,此时栈顶元素为10,仍比12小,10出栈,此时栈为空,12入栈,栈内元素为12。

当然入栈的也可以是索引,然后取出索引结合一维数组再和实际元素比较。

单调栈的运用(算法练习题)

模板

假设一维数组是 nums,ans 数组对应索引的值为 下一个大或者小的数的索引。

Stack<Integer> stack = new Stack<>();

for(int i=0;i<nums.length;++i){
	// 如果是找右边大于的一个数就是 < 号进行出栈,反之是大于进行出栈
	// 下面是找右边大于的第一个数
	while(!stack.empty() && nums[stack.peek()]<nums[i]){
		ans[stack.peek()] = i;// 这里根据具体题目进行定义ans 数组,要长度就索引,要那个大的数的值就 nums[i] 值
		stack.pop();
	}
	stack.push(i);
}

【练习一、单调栈】739. 每日温度

每日温度

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int[] ans = new int[temperatures.length];
        Arrays.fill(ans,0);// 初始化
        Stack<Integer> stack = new Stack<>();
        for(int i=0;i<temperatures.length;++i){
            while(!stack.empty() && temperatures[stack.peek()]<temperatures[i]){
                ans[stack.peek()] = i - stack.peek();// 直接处理得出答案
                stack.pop();
            }
            stack.push(i);
        }
        stack.clear();
        return ans;
    }
}

【练习二、单调栈+哈希表】496. 下一个更大元素 I

下一个更大元素 I

class Solution {
    private Map<Integer,Integer> map = new HashMap<>();
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        init(nums2);
        int[] temp = new int[nums2.length];// 存nums2 中每个数的右边更大的元素
        Arrays.fill(temp,-1);// 初始化
        Stack<Integer> stack = new Stack<>();
        for(int i=0;i<nums2.length;++i){
            while(!stack.empty() && nums2[stack.peek()]<nums2[i]){
                temp[stack.peek()] = nums2[i];
                stack.pop();
            }
            stack.push(i);
        }
        int[] ans = new int[nums1.length];
        for(int i=0;i<nums1.length;++i){
            ans[i] = temp[map.get(nums1[i])];
        }
        return ans;
    }
    /**
        这是对map 集合进行初始化,把nums2 数组中数的索引记录下来
     */
    private void init(int[] nums){
        for(int i=0;i<nums.length;++i)
            map.put(nums[i],i);
    }
}

【练习三、单调栈+循环数组】503. 下一个更大元素 II

下一个更大元素 II

class Solution {
    public int[] nextGreaterElements(int[] nums) {
        int len = nums.length*2;// 循环数组
        Deque<Integer> stack = new ArrayDeque<>();// 单调递增栈,存放索引
        int[] ans = new int[nums.length];
        Arrays.fill(ans,-1);// 初始化
        
        for(int i=0;i<len;++i){
            while(!stack.isEmpty() && nums[stack.peek()]<nums[i%nums.length]){
                ans[stack.peek()] = nums[i%nums.length];
                stack.pop();
            }
            stack.push(i%nums.length);
        }
        return ans;
    }
}

【练习四、单调栈】👍42.接雨水

接雨水

听说这是高频面试题;
解题的方法不唯一(这里使用的是单调栈的解法):

  1. 双指针
  2. 动态规划
  3. 单调栈

解这题是思路就两种,按行求雨水,按列求雨水。

在这里插入图片描述

使用单调栈来解这题是使用行来计算的。

class Solution {
    public int trap(int[] height) {
        Deque<Integer> stack = new ArrayDeque<>();// 存放索引,单调递增栈
        int sum = 0;
        for(int i=0;i<height.length;++i){
            while(!stack.isEmpty() && height[stack.peek()]<height[i]){
                // 产生凹型的时候才会接住雨水
                // 这是凹形中间柱
                int midH = height[stack.peek()];
                stack.pop();
                // 获取产生高度差的最低柱子
                if(!stack.isEmpty()){
                    int minH = Math.min(height[i],height[stack.peek()]);
                    int len = i - stack.peek() - 1;
                    sum += (minH-midH)*len;
                }
            }
            stack.push(i);
        }
        return sum;
    }
}

【练习五、单调栈】👍84. 柱状图中最大的矩形

柱状图中最大的矩形

这题把我头给整大了。和上面一题有类似的地方,但不多。
动态规划解决这题可能更好写些。单调栈解决这题,需要创建新数组,在原数组的首尾加上0,想到这里了就见到了,单调栈中仍存放索引,对应的数是单调递增的,然后遇到小于它的数,可以对左右边界然后计算其最大面积然后与ans进行比较。

class Solution {
    public int largestRectangleArea(int[] heights) {
        int len = heights.length;
        List<Integer> newH = new ArrayList<>();
        newH.add(0);
        for(int h:heights){
            newH.add(h);
        }
        newH.add(0);
        // 制作新的数组,在原来基础上,左右加个0高度柱子
        // 最左边的0是为了第一个小数
        // 最右边的是为了情况单调栈
        Deque<Integer> stack = new ArrayDeque<>();// 存放左边第一个小的数的索引,单调递增栈
        int ans = 0;
        for(int i=0;i<newH.size();++i){
            while(!stack.isEmpty() && newH.get(stack.peek())>newH.get(i)){
                int mid = stack.peek();
                stack.pop();
                int left = stack.peek();// 左边最小索引
                int right = i;// 右边最小索引
                ans = Math.max((right-left-1)*newH.get(mid),ans);
            }
            stack.push(i);
        }
        return ans;
    }
}

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

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

相关文章

Word处理控件Aspose.Words功能演示:使用 C++ 处理 Word 文档中的目录

Aspose API支持流行文件格式处理&#xff0c;并允许将各类文档导出或转换为固定布局文件格式和最常用的图像/多媒体格式。 Aspose.words是一种高级Word文档处理API&#xff0c;用于执行各种文档管理和操作任务。API支持生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现和…

4EVERLAND IPFS CID部署,一键部署Uniswap

近日&#xff0c;4EVERLAND推出IPFS CID部署&#xff0c;开发者可以复制IPFS CID&#xff0c;一键部署到4EVERLAND。 一键部署&#xff0c;无需通过Github Repo&#xff0c;只需要知道CID即可。一键跨平台部署项目到 Arweave 或 ICP。了解IPFS CID&#xff0c;通过4EVERLAND绑…

漫谈广告机制设计 | 开篇语

很久没有写文章了&#xff0c;oCPC实践录的专栏还没有写完&#xff0c;我就换工作了&#xff0c;去了M公司&#xff0c;做的内容与oCPC不怎么相关&#xff0c;对于其中的问题思考也没有那么多了&#xff0c;好在专栏的核心思想已经基本阐明了。在M公司也已经快两年了&#xff0…

青龙+WxPusher实现资产推送

1.首先注册WXpusher&#xff1a; https://wxpusher.zjiecode.com/admin/login 扫码注册创建应用 确定完就会出现一个token&#xff0c;一定先复制保存起来&#xff0c;因为只显示一次&#xff0c;没存后期就只能重置了。 关闭后&#xff0c;这个页面有二维码和链接&#xff0…

CSS定位详解

文章目录定位为什么要使用定位定位的组成定位模式静态定位&#xff1a;按照标准流特性摆放&#xff0c;没有边偏移相对定位&#xff1a;元素在移动位置的时候&#xff0c;是相对于它原来的位置来说的绝对定位&#xff1a;在移动位置的时候相对与祖先元素固定定位&#xff1a;元…

C语言:指针详解

往期文章 C语言&#xff1a;初识C语言C语言&#xff1a;分支语句和循环语句C语言&#xff1a;函数C语言&#xff1a;数组C语言&#xff1a;操作符详解 目录往期文章前言1. 指针是什么2. 指针和指针类型3. 野指针4. 指针运算4.1 指针-整数4.2 指针-指针4.3 指针的关系运算5. 二…

“小灵通”的风雨往事

最近&#xff0c;有一部叫做《狂飙》的国产电视剧火遍全网&#xff0c;相信大家都看到了。在剧中&#xff0c;出现了一个通信名词&#xff0c;不知道在座各位有没有关注到。没错&#xff0c;这个名词&#xff0c;就是“小灵通”。《狂飙》剧的主角高启强&#xff0c;原本是个卖…

Web3.0 · 基础层技术 · SCQA模型趣谈密码学

【小木箱成长营】密码学系列教程&#xff1a; Web3.0 基础层技术 密码学在移动端应用与实践 一、序言 Hello&#xff0c;我是小木箱&#xff0c;欢迎来到小木箱成长营密码学系列教程&#xff0c;今天将分享 Web3.0 基础层技术 SCQA 模型趣谈密码学。 SCQA 模型趣谈密码学主…

第一章 opencv与python介绍及环境搭建

目录1.python安装2.opencv3.pycharm安装4.conda环境搭建(my)1.python安装 网上教程很多就不写了&#xff0c;推荐使用python3.8.2及以上版本 2.opencv opencv简单介绍&#xff1a;opencv是一个开源的计算机视觉库&#xff0c;可以在windows、MacOS、Linux等操作系统上运行。 …

Day878.count(*)问题 -MySQL实战

count(*)问题 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于count(*)问题。 在开发系统的时候&#xff0c;可能经常需要计算一个表的行数&#xff0c;比如一个交易系统的所有变更记录总数。 这时候可能会想&#xff0c;一条 select count(*) from t 语句不就解决…

【自动化测试】从0开始玩转docker—— 02软件配置

目的 CI / CD在目前各类互联网企业中已然成为推动软件开发行为的重要基础设施服务。同样的对于测试团队来说更是有着举足轻重的重大意义&#xff0c;无论是测试左移的具象化提现亦或是持续测试的顺利开展&#xff0c;掌握这一技能已是广大软件测试工程师的必修课。分享这一技术…

第一章:3D点云应用领域分析

&#x1f31e;欢迎来到点云的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; ✉️希望可以和大家一起完成进阶之路&#xff01; &#x1f64f;作者…

力扣(LeetCode)401. 二进制手表(2023.02.03)

二进制手表顶部有 4 个 LED 代表 小时&#xff08;0-11&#xff09;&#xff0c;底部的 6 个 LED 代表 分钟&#xff08;0-59&#xff09;。每个 LED 代表一个 0 或 1&#xff0c;最低位在右侧。 例如&#xff0c;下面的二进制手表读取 “3:25” 。 &#xff08;图源&#xff…

C语言基础知识(56)

下面的C程序的输出是什么#include<stdio.h>intmain(){int a 0;while(a <printf("HI")){a;}return0;}该代码将打印 3 次HI。 printf()函数将返回它正在打印的字符数&#xff0c;并将其与a进行比较。 由于 printf() 的返回值为 2&#xff0c;HI 将被打印 2 次…

字符函数和字符串函数

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a;C语言学习笔记 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 目录 前言 一、字符串函数 1. 1 strlen 2. 长度不受限制的字符串函数&#xff08;操作的是整个字符串&#…

Linux-用户权限相关命令

1.用户和权限的基本概念1.1基本概念用户是Linux系统工作中重要的一环&#xff0c;用户管理包括用户与组管理在Linux系统中&#xff0c;不论是由本机或是远程登录系统&#xff0c;每个系统都必须拥有一个账号&#xff0c;并且对于不同的系统资源拥有不同的使用权限在Linux中&…

DAMA数据管理知识体系指南之数据操作管理

第6章 数据操作管理 6.1 简介 数据操作管理是结构化数据的开发、维护和支持的活动&#xff0c;使企业数据资源达到最佳的利用价值。数据操作管理包括两项子职能&#xff1a;数据库支持和数据技术管理。 数据操作管理的目标是&#xff1a; &#xff08;1&#xff09;保护和确保…

SpringBoot 如何保证接口安全?老鸟们都是这么玩的!

大家好&#xff0c;我是飘渺。 对于互联网来说&#xff0c;只要你系统的接口暴露在外网&#xff0c;就避免不了接口安全问题。如果你的接口在外网裸奔&#xff0c;只要让黑客知道接口的地址和参数就可以调用&#xff0c;那简直就是灾难。 举个例子&#xff1a;你的网站用户注册…

【NS2学习笔记】tcl与c++互相调用/传参

在NS2&#xff0c;做实验的时候&#xff0c;为了能通过循环配合传值实验&#xff0c;一直找不到tcl传参给c的方法&#xff0c;网上的只po出一部分看不懂&#xff0c;只能通过源码自己研究。最后的解决办法就是&#xff0c;模仿源码的操作&#xff0c;以下通过tcl→ex→sat-irid…

Python如何删除列表中的重复元素?

嗨嗨&#xff0c;大家晚上好 ~ 又来给你们分享小妙招啦 在python列表有重复元素时&#xff0c;可以有以下几种方式进行删除 觉得不错的话&#xff0c;赶紧学起来用用吧 &#xff01; 直接遍历列表删除 l1 [1, 1, 2, 2, 3, 3, 3, 3, 6, 6, 5, 5, 2, 2]for el in l1:if l1.coun…