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

news2025/3/13 4:11:59

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

今天没有小故事。

参考以及题单来源:

代码随想录 (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的集合框架重新复写,也算是有始有终。

夹带私货环节虽迟但到:

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

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

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

相关文章

递归算法讲解2

前情提要 上一篇递归算法讲解在这里 递归算法讲解&#xff08;结合内存图&#xff09; 没看过的小伙伴可以进去瞅一眼&#xff0c;谢谢&#xff01; 递归算法的重要性 递归算法是非常重要的&#xff0c;如果想要进大厂&#xff0c;以递归算法为基础的动态规划是必考的&…

Android安卓开发 - 简单介绍(一)

最近呢需要重构还有维护安卓项目&#xff0c;所以最近会从零开始梳理开发的一些知识点以及开发的内容 前面已经写了安装的教程&#xff0c;idea怎么安装&#xff0c;还有官方的开发工具Android Studio怎么安装 2024最新版Android studio安装入门教程&#xff08;非常详细&…

SpringBoot整合ELK8.1.x实现日志中心教程

目录 背景 环境准备 环境安装 1.JDK安装 2.安装Elasticsearch 3.安装zookeeper 4.安装Kafka 5.安装logstash 6.安装file beat 解决方案场景 1.日志采集 1.1 应用日志配置 1.1.1 创建logback-spring.xml文件 1.1.2 创建LoggerFactory 1.1.3 trace日志的记录用法 …

K8S- Deployment 的滚动更新 Rolling Update

滚动更新 这里的更新指的不是更新deployment 本身的属性(label/ replicas)等&#xff0c; 而是更新POD 的container 的版本 更新方法通常有两种 是直接update deployment配置&#xff0c; 注意只有update了template中的内容(与container相关) 才会触发更新用kubectl set ima…

C++ | Leetcode C++题解之第7题整数反转

题目&#xff1a; 题解&#xff1a; class Solution { public:int reverse(int x) {int rev 0;while (x ! 0) {if (rev < INT_MIN / 10 || rev > INT_MAX / 10) {return 0;}int digit x % 10;x / 10;rev rev * 10 digit;}return rev;} };

鸿宇多用户商城 scan_list.php SQL注入漏洞复现

0x01 产品简介 鸿宇多用户商城是一款支持各行业的多商家入驻型电商平台系统,商家版APP,微信商城,小程序及各种主流营销模块应有尽有,是一个功能强大的电子商务平台,旨在为企业和个人提供全面的在线购物解决方案。 0x02 漏洞概述 鸿宇多用户商城 scan_list.php 文件 data[fa…

Python 网络请求:深入理解Requests库

目录 引言 一、Requests库简介 二、安装与基本使用 三、requests库的特性与优势 四、requests库在实际应用中的案例 1.get请求 2.post请求 3.超时重试 4.headers设置 5.session会话 6.携带cookie​​​​​​​ 7.携带代理​​​​​​​ 8.携带身份认证​​​​​…

FLink学习(三)-DataStream

一、DataStream 1&#xff0c;支持序列化的类型有 基本类型&#xff0c;即 String、Long、Integer、Boolean、Array复合类型&#xff1a;Tuples、POJOs 和 Scala case classes Tuples Flink 自带有 Tuple0 到 Tuple25 类型 Tuple2<String, Integer> person Tuple2.…

InternLM2-lesson2作业

书生浦语大模型趣味 Demo 视频连接&#xff1a;https://www.bilibili.com/video/BV1AH4y1H78d/?vd_source902e3124d4683c41b103f1d1322401fa 目录 书生浦语大模型趣味 Demo一、基础作业二、进阶作业 一、基础作业 第一次执行&#xff1a; 第二次执行&#xff1a; 第一次执…

最新408试卷分析+备考经验分享

408出题再糟糕&#xff0c;你是不是还是要考&#xff1f; 别管出题人出多刁钻的题&#xff0c;大家拿到的卷子都是一样的&#xff0c;要难就都难&#xff0c;要刁钻就一起g... 所以再潜心钻研出题规律或出题套路&#xff0c;不如多花些时间去多复习巩固几遍知识点&#xff01…

Leetcode_2两数相加

文章目录 前言一、两数相加1.1 问题描述1.2 解法一&#xff1a;分别将链表转为数字&#xff0c;然后相加1.3 代码实现1.4 解法二&#xff1a;分别将对应位置数字相加1.5 代码实现 二、使用步骤1.引入库2.读入数据 前言 链表是一种物理内存非连续存储&#xff0c;非顺序的线性数…

深入理解C/C++的内存管理

在C和C中&#xff0c;高效的内存管理是编写性能优化和资源高效利用程序的关键。本文将深入探讨C/C内存管理的各个方面&#xff0c;包括内存的分布、C语言和C中的动态内存管理方式&#xff0c;以及new和delete操作符的使用 C/C内存分布 C和C程序的内存可以分为以下几个区域&…

【Linux】-进程知识铺垫①计算机硬件的组织:冯诺依曼体系结构详细解读②关于操作系统对软硬件及用户的意义

目录 ​编辑 1.关于计算机的体系结构 1.1 冯诺依曼体系结构的诞生 2.冯诺依曼体系结构 2.1 cpu:运算器&#xff1a;更多的是让cpu具有特殊的数据计算功能&#xff1a; 2.2 控制器 2.3输入设备 2.4输出设备 3.计算机各个硬件设备之间的关系 4.内存与计算机效率 5.关于为什么总说…

AI智能校色解决方案,专业级画质提升

由于拍摄环境、设备性能以及编辑经验等多种因素的影响&#xff0c;视频画质往往难以达到理想状态。这时&#xff0c;一款高效、智能的校色解决方案就显得尤为重要。美摄科技凭借深厚的图像处理技术和AI算法研发实力&#xff0c;推出了全新的AI智能校色解决方案&#xff0c;助力…

Kubernetes(k8s)核心资源解析:Pod详解

Kubernetes核心资源解析&#xff1a;Pod详解 1、什么是Pod&#xff1f;2、Pod 的组成3、Pod 如何管理多个容器4、Pod 的网络5、Pod 的存储方式6、Pod 的工作方式6.1 自主式 Pod6.2 监控和管理 Pod6.3 Pod 的创建流程 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收…

力扣热题100_链表_2_两数相加

文章目录 题目链接解题思路解题代码 题目链接 2. 两数相加 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 …

网络安全 | 什么是云安全?

关注WX&#xff1a;CodingTechWork 云安全-介绍 云安全是为了解决企业安全所面临的外部和内部威胁&#xff0c;它是一组程序和技术的集合。企业在实施其数字化转型策略&#xff0c;并将各种云端工具和服务纳入企业基础架构中时&#xff0c;需要云安全保障业务顺利进行。 云计…

ComfyUI ClipSeg插件报错- resize_image出错应该怎么办

上一篇刚介绍了这个插件&#xff0c;结果emm..很快发现事情并不简单...结果又报错了。 后台报错信息&#xff1a; Unused or unrecognized kwargs: padding. !!! Exception during processing !!! Traceback (most recent call last): File "F:\ComfyUI-aki\execution.p…

蓝桥杯练习笔记(十七)

蓝桥杯练习笔记&#xff08;十七&#xff09; 一、 输入样例 7 7 1000001 0100010 0010100 0001AAA 00010A0 00010A0 00010A0蓝桥官网题解&#xff1a; 该题解是用了三个循环分别对三个方向的相同字符的长度进行统计&#xff0c;找出最大长度&#xff0c;最后对找出的最长Y进…

Finite Element Procedures K.J.Bathe 【教材pdf+部分源码】|有限元经典教材 | 有限元编程

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…