【算法】单单单单单调栈,接接接接接雨水

【算法】单单单单单调栈,接接接接接雨水

今天没有小故事。

参考以及题单来源:

代码随想录 (programmercarl.com)

Part 1 啥是单调栈?

1.啥啥啥是单调栈?

栈的特性想必各位再熟悉不过了:先进后出。栈仅仅有一个出口,故而先进入的会被压到栈底,而想取出元素时,则必须从栈顶开始取。

而单调栈,就是在入栈的时候加了一则限制条件:

入栈的元素必须大于(或者小于)栈顶元素,否则弹出栈顶元素,直到满足条件再压入新元素,从而使得栈内元素满足单调递增或者单调递减的规律。

2.这这这是单调栈!

光说不画假把戏,上图!

此处以单调递增栈为例:

QQ图片20240404205420

Part 2 现在你已经完全学会了单调栈,那我们来试试题吧!.JPG

503.下一个更大元素 ||

原题链接:

503. 下一个更大元素 II - 力扣(LeetCode)

image-20240404194646346

寻找下一个更大元素,只需要套用单调栈的模板即可,唯一的不同在于,这里在一个循环数组中寻找对应元素,也很简单,将同样的两个链表拼接在一起(模拟遍历一圈)再求值即可。

值得注意的是,由于将两个链表拼接在了一起,ans数组的大小就不好确定,这里将迭代器中的每个i都用数组大小取模,解决了这个问题。

if(!st.isEmpty() && nums[st.peek()] < nums[i % lens]){
    while(!st.isEmpty() && nums[st.peek()] < nums[i % lens]){
        ans[st.peek()] = nums[i % lens];
        st.pop();
    }
    st.push(i % lens);
}else{
    st.push(i % lens);
}

同时,如果不存在想寻找的数字,则输出-1,由于这条规则,我们调用fill方法,将数组初始化为-1。

Arrays.fill(ans,-1);

AC代码如下:

class Solution {
    public int[] nextGreaterElements(int[] nums) {
        Stack<Integer> st = new Stack<>();
        int lens = nums.length;
        int[] ans = new int[lens];
        Arrays.fill(ans,-1);
        //遍历两次数组,同时对i取模,模拟循环遍历
        for(int i = 0;i < lens*2;++i){
            //单调栈模板~猛猛套用
            //下一个最大元素,故而维护栈底到栈顶单调递减
            if(!st.isEmpty() && nums[st.peek()] < nums[i % lens]){
                while(!st.isEmpty() && nums[st.peek()] < nums[i % lens]){
                    ans[st.peek()] = nums[i % lens];
                    st.pop();
                }
                st.push(i % lens);
            }else{
                st.push(i % lens);
            }
        }
        return ans;
    }
}
//执行用时过高,但代码时间复杂度已经较低。初步判断可能是new对象导致、
//在较低执行用时的题解中发现有人用Array实现的Deque双端队列,同样的思路但其时间复杂度较低,可能是底层框架的问题。

739.每日温度

原题链接:

739. 每日温度 - 力扣(LeetCode)

image-20240404210530197

这道题仍然可以通过遍历解决,但遍历的方式显然时间复杂度过高(比上题还高),所以这道题试着使用单调栈来解决。

维护一个单调栈,如果发现小于栈顶元素则入栈,发现大于栈顶元素,就相当于找到了下一个更大的元素,则将栈顶元素出栈,再把新的元素入栈,每出一个元素,就相当于找到了一个更大的元素。

值得一提的是其中一句Arrays.fill这句代码,将答案数组全部元素填充为0,表示气温如果没有升高的情况,则用0代替。(虽然在java中数组默认的初始值都是0)

Arrays.fill(ans,0);

AC代码如下:

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        Stack<Integer> st = new Stack<>();
        int len = temperatures.length;
        int[] ans = new int[len];
        Arrays.fill(ans,0);
        for(int i = 0;i < len;++i){
            if(!st.isEmpty() && temperatures[i] > temperatures[st.peek()]){
                //如果大于栈顶元素则出栈,并维护栈的单调递增(由顶到底)
                while(!st.isEmpty()&&temperatures[i]>temperatures[st.peek()]){
                    ans[st.peek()]=i-st.peek();
                    st.pop();
                }
                st.push(i);
            }else{
                //如果发现小于等于栈顶元素则入栈
                st.push(i);
            }
        }
        return ans;
    }
}
//Tip:题解中时间复杂度较低的答案,使用数组模拟栈进行操作。

42.接雨水

原题链接:

42. 接雨水 - 力扣(LeetCode)

image-20240404212736337

再来一道模拟单调栈的题目(其实早就写了但现在才做题解)。

当遍历墙的高度的时候,如果当前高度小于栈顶的墙高度,说明这里会有积水,我们将墙的高度的下标入栈。

如果当前高度大于栈顶的墙的高度,说明之前的积水到这里停下,我们可以计算下有多少积水了。计算完,就把当前的墙继续入栈,作为新的积水的墙。

当前高度小于等于栈顶高度,入栈。

当前高度大于栈顶高度,出栈,计算出当前墙和栈顶的墙之间水的多少,然后计算当前的高度和新栈的高度的关系,重复第 2 步。直到当前墙的高度不大于栈顶高度或者栈空,然后把当前墙入栈。

while(!st.isEmpty() && height[st.peek()] < height[i]){
    int cur = st.pop();
    if(st.isEmpty()){
        break;
    }
    int l = st.peek();
    int r = i;
    int h = Math.min(height[r],height[l]) - height[cur];
    ans += (r - l - 1) * h;
}

AC代码如下:

class Solution {
    public int trap(int[] height) {
        int ans = 0;
        //创建一个栈
        Stack<Integer> st = new Stack<>();
        for(int i = 0;i < height.length;++i){
            while(!st.isEmpty() && height[st.peek()] < height[i]){
                //cur表示水洼的底部
                int cur = st.pop();
                if(st.isEmpty()){
                    break;
                }
                //获取水池的左右两端的墙的下标。
                int l = st.peek();
                int r = i;
                int h = Math.min(height[r],height[l]) - height[cur];
                ans += (r - l - 1) * h;
            }
            st.push(i);
        }
        return ans;
    }
}

结语:

其实很久以前就写过单调栈的相关题目,也了解过单调栈的代码,但这篇博客一直留着迟迟没发,如今将其从箱底翻出,用Java的集合框架重新复写,也算是有始有终。

夹带私货环节虽迟但到:

百发失一,不足谓善射;千里跬步不至,不足谓善御;伦类不通,仁义不一,不足谓善学。学也者,固学一之也。一出焉,一入焉,涂巷之人也;其善者少,不善者多,桀纣盗跖也;全之尽之,然后学者也。

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

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

相关文章

算法 day29 回溯5

491 非递减子序列 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如出现两个整数相等&#xff0c;也可以视作递增序列的一种特殊情…

检测头篇 | 利用RT-DETR模型的检测头去替换YOLOv8中的检测头

前言:Hello大家好,我是小哥谈。RT-DETR号称是打败YOLO的检测模型,其作为一种基于Transformer的检测方法,相较于传统的基于卷积的检测方法,提供了更为全面和深入的特征理解,将RT-DETR检测头融入YOLOv8,我们可以结合YOLO的实时检测能力和RT-DETR的深度特征理解能力,打造出…

业务网关的设计与实践

在过去的两年里&#xff0c;主要在做业务网关的开发。今年春节后选择转岗去做更偏近业务的开发。公司的业务是金融相关&#xff0c;一直觉得金融相关的业务是有一定门槛并且是对职业生涯有帮助的&#xff0c;所以趁这个机会来深入了解这块业务。 仔细回想&#xff0c;在做业务…

【数据处理包Pandas】数据载入与预处理

目录 一、数据载入二、数据清洗&#xff08;一&#xff09;Pandas中缺失值的表示&#xff08;二&#xff09;与缺失值判断和处理相关的方法 三、连续特征离散化四、哑变量处理 准备工作 导入 NumPy 库和 Pandas 库。 import numpy as np import pandas as pd一、数据载入 对…

开机自启动

对win10,给一种开机自启动的设置方法: 1. winr 打开 2. 输入shell:startup打开 开始\程序\启动 3. 把想要自启动的应用的快捷方式放在这里即可 亲测有用

第十一届蓝桥杯物联网试题(省赛)

对于通信方面&#xff0c;还是终端A、B都保持接收状态&#xff0c;当要发送的数组不为空再发送数据&#xff0c;发送完后立即清除&#xff0c;接收数据的数组不为空则处理&#xff0c;处理完后立即清除&#xff0c;分工明确 继电器不亮一般可能是电压不够 将数据加空格再加\r…

RPA自动化小红书自动化写文以及发文!

1、视频演示 RPA自动化小红书自动写作发文 2、核心功能点 采集笔记&#xff1a;采集小红书上点赞量大于1000的爆款笔记 下载素材&#xff1a;下载爆款笔记的主图 爆款改写&#xff1a;根据爆款笔记的标题仿写新的标题以及新的文案 自动发布&#xff1a;将爆款笔记发布到小红…

Oracle RAC One Node,双胞胎变独生子?

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

LeetCode刷题实战2:两数相加

在日常我们学习数据结构和算法的知识&#xff0c;一定不能只停留在看书、看视频层面&#xff0c;一定要自己多练习&#xff0c;纸上得来终觉浅&#xff0c;绝知此事要躬行。 题目内容 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存…

Vue3:组件间通信-$attrs的使用

一、情景说明 我们之前学习了通过props实现&#xff0c;父给子传数据 那么&#xff0c;如果&#xff0c;父组件给子组件传递多个数据&#xff0c;但是&#xff0c;子组件只用props声明了一个数据 其他数据去哪里了呢&#xff1f; 二、案例 1、父组件 <Child :a"a&…

Linux 关闭防火墙命令(新手)

关闭防火墙 查看防火墙状态 systemctl status firewalld.service 临时关闭防火墙&#xff08;重启失效&#xff09; systemctl stop firewalld.service 永久关闭防火墙 systemctl disable firewalld.servicesudo systemctl enable firewalld&#xff0c;这种方式输入命令…

AcWing 731. 毕业旅行问题(每日一题)

原题链接&#xff1a;731. 毕业旅行问题 - AcWing题库 此题难度较大&#xff0c;是2019年字节跳动校招题&#xff0c;里面涉及位运算与状态压缩DP&#xff0c;不会的可以去学习&#xff0c;此题根据个人量力而行。 建议看一下y总的讲解&#xff1a;AcWing 731. 毕业旅行问题&…

【Unity 实用工具篇】| Unity中 实现背景模糊效果,简单易用

前言【Unity 实用工具篇】| Unity 实现背景模糊效果,简单易用一、实现背景模糊效果1.1 介绍1.2 效果展示1.3 使用说明及下载二、插件资源简单介绍2.1 导入下载好的资源2.2 功能介绍2.2.1 捕获特效2.2.2 高级选项

长连接详解

一分钟了解长连接 、短连接、心跳机制与断线重连 - 知乎 (zhihu.com) websocket 实现长连接原理_websocket 是长连接吗-CSDN博客

RedisDesktopManager 安装

简介&#xff1a;安装redis可视化工具 一、下载压缩包 Redis 可视化工具 链接&#xff1a;https://pan.baidu.com/s/1P2oZx9UpQbXDsxJ3GPUeOQ 提取码&#xff1a;6rft Redis 命令窗口版本 链接&#xff1a;https://pan.baidu.com/s/1mIuxCEWwD__aoqp1Cx8MFQ 提取码&#xf…

Linux 文件相关命令

一、查看文件命令 1&#xff09;浏览文件less 默认查看文件的前 10 行。 less /etc/services ##功能说明&#xff1a; #1.默认打开首屏内容 #2.按【回车】按行访问 #3.按【空格】按屏访问 #4.【从上向下】搜索用/111,搜索包含111的内容&#xff0c;此时按n继续向下搜&#x…

力扣刷题 45.跳跃游戏 II

目录 题干 解题思路 题干 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n…

稀碎从零算法笔记Day39-LeetCode:有向无环图中一个节点的所有祖先

感觉写的越来越难了hhh&#xff0c;一晚上只研究明白了2道题 题型&#xff1a;拓扑排序、BFS、图 链接&#xff1a;2192. 有向无环图中一个节点的所有祖先 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述&#xff08;红字为笔者添加&#xff0…

FPGA实现Canny算法(Verilog)

在边缘检测算法里面Sobel是比较简单的一个算法&#xff0c;但是其检测出来的边缘往往是比较粗的&#xff0c;效果不是很好&#xff0c;因为我们最理想的边缘肯定就是一个宽度为1的细线。 Canny算法在此基础上进行了改进&#xff0c;通过使用边缘的梯度信息进行非最大值抑制(NM…

基于单片机的数字万用表设计

**单片机设计介绍&#xff0c;基于单片机的数字万用表设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的数字万用表设计概要是关于使用单片机技术来实现数字万用表功能的一种设计方案。下面将详细概述该设计的各个…