力扣题目汇总分析 利用单调栈解决问题

news2024/11/25 12:26:52

496 下一个更大元素 I

问题

nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。为nums1中每个数字 x找到下一个更大元素。如果不存在下一个更大元素,那么本次查询的答案是 -1

示例 1:

输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:

  • 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
  • 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
  • 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
分析

可以暴力法通过两层循环来实现,但是会超时。
使用暴力法,我们需要为nums1中每个元素 遍历nums2找到对应位置然后继续遍历确定下一个最大元素。
可不可以不遍历nums2,直接访问哈希表得到下一个最大元素呢?让哈希表的key是nums2中的每个元素值,value就是key对应的nums2中的下一个最大元素!
使用单调栈来构建这个哈希表!
找右侧(下一个)最大元素,从右往左遍历nums2,找右边出现的第一个大的元素,所以所有新元素都要入栈,然后构建出一个从下往上(从左往右)看单调递减的栈。
示例1,
倒数第一个元素2,栈空,记录d[4]=-1,把2入栈;【栈:2】
倒数第二个元素4,4大于栈顶元素2,弹出2,栈空,记录d[3]=-1,把4入栈;【栈:4】
倒数第三个元素3,3小于栈顶元素4,记录d[1]=4,把3入栈,满足单调递减;【栈:4,3】
倒数最后一个元素1,1小于栈顶元素3,记录d[0]=3,把1入栈,满足单调递减。【栈:4,3,1】

代码实现
class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        //key:nums2中每个不重复的元素 value:每个元素对应的下一个最大元素
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        Stack<Integer> stack=new Stack<Integer>();
        int[] l=new int[nums1.length];
        for (int i=nums2.length-1;i>=0;i--){
            while (!stack.empty()&&stack.peek()<=nums2[i]){
                stack.pop();
            }
            if (stack.empty()){
                map.put(nums2[i],-1);
            }else{
                map.put(nums2[i],stack.peek());
            }
            stack.push(nums2[i]);
        }
        for (int i=0;i<nums1.length;i++){
            l[i]=map.get(nums1[i]);
        }
        return l;
    }
}

901 股票价格跨度

问题

设计一个算法收集某些股票的每日报价,并返回该股票当日价格的 跨度 。

当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。

例如,如果未来 7 天股票的价格是 [100,80,60,70,60,75,85],那么股票跨度将是 [1,1,1,2,1,4,6] 。

实现 StockSpanner 类:

StockSpanner() 初始化类对象。
int next(int price) 给出今天的股价 price ,返回该股票当日价格的 跨度 。

示例:

输入:
[“StockSpanner”, “next”, “next”, “next”, “next”, “next”, “next”, “next”]
[[], [100], [80], [60], [70], [60], [75], [85]]
输出:
[null, 1, 1, 1, 2, 1, 4, 6]

解释:
StockSpanner stockSpanner = new StockSpanner();
stockSpanner.next(100); // 返回 1
stockSpanner.next(80); // 返回 1
stockSpanner.next(60); // 返回 1
stockSpanner.next(70); // 返回 2
stockSpanner.next(60); // 返回 1
stockSpanner.next(75); // 返回 4 ,因为截至今天的最后 4 个股价 (包括今天的股价 75) 都小于或等于今天的股价。
stockSpanner.next(85); // 返回 6

分析

和前一个题目思路一样,有两点不同

  1. 只是这相当于找前一个更大元素,力扣内部机制就是从左往右输入每日price,符合!(如果是前一题那种有个nums2,那么我们从左到右遍历nums2,来为每个数组元素找到前一个更大元素)
  2. 返回更大元素和当前元素之间的跨度,且是依次调用next方法找到前一个更大元素,所以不需要哈希表来存值。每次入栈的除了元素值(用来比较栈顶和即将入栈元素,构建单调递减元素)还有元素index(为了求跨度),声明一个Stack<int[]> stack,此外我们在类里面定义一个成员变量来记录index的增加。
代码实现
class StockSpanner {
    Stack<int[]> stack;
    int numSum;
    
    public StockSpanner() {
        this.stack=new Stack<int[]>();
        this.numSum=0;
    }
    
    public int next(int price) {
        this.numSum+=1;
        //一个对象实例第一次调用next,栈空时的处理
        if (this.stack.empty()){
            this.stack.push(new int[]{numSum,price});
            return this.numSum;
        }
        //值更小的栈顶就丢掉
        while ((!this.stack.empty())&&(this.stack.peek()[1]<=price)){
            this.stack.pop();
        }
        int span;
        if (this.stack.empty()){
            span=this.numSum;
        }else{
            span=this.numSum-this.stack.peek()[0];
        }
        //总之新元素都要入栈
        this.stack.push(new int[]{numSum,price});
        return span;
    
    }
}

84 柱状图中的最大矩形

问题

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

在这里插入图片描述

分析

暴力法,枚举矩形的宽度,也就是搞个二层循环,起始索引i 和结束索引j ,然后高就是i,j之间最矮的那个柱子的高度。还可以枚举矩形的高度,因为可以发现矩形的高总是某个柱子的高度,枚举每个柱子高度,以该高度heights[i]作为最终矩形的高度,然后以i往左往右扩展找到柱子高度小于heights[i]的柱子,确定宽。但是这两种方法力扣上面会超时。

枚举高,我们需要为每个柱子的高度找到围成这一高度最大面积矩形的左右边界,最坏情况下遍历了n,有没有一种可能遍历高,利用单调栈来找。

因为我们是往左往右扩展找到柱子高度小于heights[i]的柱子,找前一个和下一个更小元素。如果建立一个单调递增栈,那前一个更小元素自然有了,下一个更大元素就看新来的高度,如果新来的高度小于我,那我就找到了以我为高度勾勒出的最大矩形面积,如果新来的高度大于我,那就先入栈,满足单调递增。当所有元素遍历完经历了入栈出栈等操作,栈里面剩下的都是从当前高度往后可以一直画矩形的,因为高度都大于当前高度!懂了懂了么~

显然这是找跨度,所以栈里存索引,定义一个变量maxArea保存最大面积,分析示例1:
i=0准备入栈,栈空,入栈;【栈:0】
i=1准备入栈,发现栈顶值对应柱子高度>将入栈值对应柱子高度,于是得到以2为高度勾勒的矩形最大也就area=2*1,比较maxArea看是否替换,栈顶出栈,i=1入栈;【栈:1】
i=2准备入栈,发现栈顶值对应柱子高度<将入栈值对应柱子高度,i=2入栈;【栈:1,2】
i=3准备入栈,发现栈顶值对应柱子高度<将入栈值对应柱子高度,i=3入栈;【栈:1,2,3】
i=4准备入栈,发现栈顶值对应柱子高度>将入栈值对应柱子高度,于是得到以6为高度勾勒的矩形最大也就area=6*1,比较maxArea看是否替换,栈顶出栈,继续对比!栈顶值对应柱子高度<将入栈值对应柱子高度,于是得到以6为高度勾勒的矩形最大也就area=6*(4-2),比较maxArea看是否替换,栈顶出栈,继续对比!发现栈顶值对应柱子高度<将入栈值对应柱子高度,i=4入栈;【栈:1,4】
i=5准备入栈,发现栈顶值对应柱子高度<将入栈值对应柱子高度,i=5入栈;【栈:1,4,5】

欧克!到这里遍历柱子高度完成,栈里面剩下的都是从当前高度往后可以一直画矩形的!

切忌! 呜呜,我拿示例1分析,弄错了一个地方,当遇到栈顶值对应柱子高度>将入栈值对应柱子高度,准备计算area时,千万先要先弹出栈顶元素再计算area,因为存在如下图的情况,假如此时【栈:1,5】,i=2为栈顶,heights[i]=5,栈顶值对应柱子高度>将入栈值对应柱子高度,应该先弹出可以求出以5为高度勾勒的矩形最大area=5*(3-0-1)=10
在这里插入图片描述

代码实现
class Solution {
    public int largestRectangleArea(int[] heights) {
        //需要一个栈,存索引
        Stack<Integer> stack=new Stack<Integer>();
        //需要一个变量存最大矩形面积
        int maxArea=-1;
        int tmp;
        int area;
        for (int i=0;i<heights.length;i++){
            while (!stack.empty()&&heights[stack.peek()]>heights[i]){
                //先出栈
                tmp=stack.pop();
                if (!stack.empty()){
                    //i-stack.peek()-1 还要减去1
                    area=heights[tmp]*(i-stack.peek()-1);
                }else{
                    area=heights[tmp]*(i-(-1)-1);
                }
                maxArea=area>maxArea?area:maxArea;
            }
            stack.push(i);
        }
        while (!stack.empty()){
            tmp=stack.pop();
            if (!stack.empty()){
                area=heights[tmp]*(heights.length-stack.peek()-1);
            }else{
                area=heights[tmp]*(heights.length-(-1)-1);
            }
            maxArea=area>maxArea?area:maxArea;
        }
        return maxArea;
    }
}

42 接雨水

问题

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水
在这里插入图片描述

分析

和上一个题目很像,我们来试试利用单调栈解决。
这个问题是求接水量,什么情况下会接住水,左右两边都有比我高的柱子,接多少水?左右两边分别找到最高的柱子,取矮的那个高度减去我自己的高度,就是我的接水量。
怎么找到左边两边最高的柱子呢?
法一:好像可以利用空间利用动态规划思想,当前柱子i的左边最高柱子等于max(柱子i-1的左边最高柱子 , 柱子i-1的高度)。右边同样。
法二:栈能否帮我们解决?这题与前面不一样,不是找前一个/后一个更大元素,是找最大元素!

xxx(学完括号匹配,再来续写单调栈的解决!

代码实现
class Solution {
    public int trap(int[] height) {
        //法一
        int sum=0;
        int n=height.length;
        int[] max_left=new int[n];
        int[] max_right=new int[n];
        for (int i=1;i<n-1;i++){
            max_left[i]=Math.max(max_left[i-1],height[i-1]);
        }
        for (int i=n-2;i>0;i--){
            max_right[i]=Math.max(max_right[i+1],height[i+1]);
        }
        //现在已经得到每列的左右两边最高的柱子高度
        //然后来求每列的接水量
        for (int i=1;i<n-1;i++){
            int m=Math.min(max_left[i],max_right[i]);
            if (m>height[i]){
                sum=sum+m-height[i];
            }
        }
        return sum;

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

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

相关文章

nvm 的安装与管理 node.js

文章目录 下载 nvm使用 nvm 下载与管理 node.jsnpm 切换镜像源使用 cnpm使用 yarn 下载 nvm NVM是Node.js的版本管理工具&#xff0c;它允许你轻松地在同一台机器上安装和切换不同版本的Node.js。使用NVM&#xff0c;你可以在不同的项目中使用不同的Node.js版本&#xff0c;而…

按键+串口发送实验

摸鱼记录 Day_15 &#xff5e;(&#xffe3;▽&#xffe3;&#xff5e;)(&#xff5e;&#xffe3;▽&#xffe3;)&#xff5e; review 前边已经学习了&#xff1a; 串口发送Vivado 串口通信(UART)------串口发送-CSDN博客 按键基于状态机的按键消抖实现-CSDN博客 1. …

WanAndroid(鸿蒙版)开发的第二篇

前言 DevEco Studio版本&#xff1a;4.0.0.600 WanAndroid的API链接&#xff1a;玩Android 开放API-玩Android - wanandroid.com 1、WanAndroid(鸿蒙版)开发的第一篇 其他一些参考点&#xff0c;请参考上面的WanAndroid开发第一篇 效果 首页实现 整体布局分为头部的Banne…

ARM学习(25)链接装载高阶认识

ARM学习&#xff08;25&#xff09;链接装载高阶认识 1、例子引出 笔者先引入几个编译链接的例子来介绍一下&#xff1a; 声明无效&#xff1a;declared implicitly&#xff1f;&#xff0c;属于编译错误还是链接错误&#xff1f; 编译阶段的错误&#xff0c;属于编译错误&am…

《量子计算:下一个大风口,还是一个热炒概念?》

引言 量子计算,作为一项颠覆性的技术,一直以来备受关注。它被认为是未来计算领域的一次革命,可能改变我们对计算能力和数据处理的理解。然而,随着技术的不断进步和商业应用的探索,人们开始思考,量子计算到底是一个即将到来的大风口,还是一个被过度炒作的概念? 量子计…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的夜间车辆检测系统(深度学习代码+UI界面+训练数据集)

摘要&#xff1a;开发夜间车辆检测系统对于自动驾驶技术具有关键作用。本篇博客详细介绍了如何运用深度学习构建一个夜间车辆检测系统&#xff0c;并提供了完整的实现代码。该系统基于强大的YOLOv8算法&#xff0c;并对比了YOLOv7、YOLOv6、YOLOv5&#xff0c;展示了不同模型间…

Hadoop学习1:概述、单体搭建、伪分布式搭建

文章目录 概述基础知识Hadoop组件构成Hadoop配置文件 环境准备配置Hadoop配置下载配置环境变量 Hadoop运行模式Standalone Operation&#xff08;本地&#xff09;官方DemoWordCount单词统计Demo Pseudo-Distributed Operation&#xff08;伪分布式模式&#xff09;配置修改启动…

vscode使用remote-ssh免密连接服务器

你还在使用XShell、Hyper、FinalShell等等SSH客户端软件吗&#xff0c;作为前端的我们&#xff0c;一直在用的功能强大的开发工具vscode&#xff0c;早已实现SSH连接功能&#xff08;借助官方提供的插件&#xff09;。而且更加好用&#xff0c;可以直接打开服务器上的文件&…

使用npm版本管理工具解决npm 的EACCES permissions errors when installing packages globally错误

EACCES错误通常表示“权限被拒绝”&#xff0c;意味着您没有足够的权限来执行某个操作。在计算机领域&#xff0c;尤其是在文件系统和程序安装中&#xff0c;这个错误很常见。以下是可能导致EACCES错误的原因以及相应的解决方法&#xff1a; 文件系统权限&#xff1a;当您尝试…

❤️算法笔记❤️-(每日一刷-141、环形链表)

文章目录 题目思路解法 题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接…

【调参】如何为神经网络选择最合适的学习率lr-LRFinder-for-Keras

【调参】如何为神经网络选择最合适的学习率lr-LRFinder-for-Keras_学习率选择-CSDN博客文章浏览阅读9.2k次&#xff0c;点赞6次&#xff0c;收藏55次。keras 版本的LRFinder&#xff0c;借鉴 fast.ai Deep Learning course。前言学习率lr在神经网络中是最难调的全局参数&#x…

YOLOv9改进 添加可变形注意力机制DAttention

一、Deformable Attention Transformer论文 论文地址:arxiv.org/pdf/2201.00520.pdf 二、Deformable Attention Transformer注意力结构 Deformable Attention Transformer包含可变形注意力机制,允许模型根据输入的内容动态调整注意力权重。在传统的Transformer中,注意力是…

Qt 如何搭建lua的运行环境

一、lua简介 Lua 是一种强大的、高效的、轻量级的、可嵌入的脚本语言。它支持过程&#xff08;procedural&#xff09;编程、面向对象编程、函数式编程以及数据描述。Lua 是动态类型的&#xff0c;运行速度快&#xff0c;支持自动内存管理&#xff0c;因此被广泛用于配置、脚本…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Select)

提供下拉选择菜单&#xff0c;可以让用户在多个选项之间选择。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口 Select(options: Array<SelectOption>) 参数&#xff1a;…

HUAWEI 华为交换机 配置 MAC 地址漂移检测示例

组网需求 如 图 2-17 所示&#xff0c;网络中两台 LSW 间网线误接形成了网络环路&#xff0c;引起 MAC 地址发生漂 移、MAC 地址表震荡。 为了能够及时检测网络中出现的环路&#xff0c;可以在 Switch 上配置 MAC 地址漂移检测功能&#xff0c; 通过检测是否发生MAC 地址漂移…

网络学习:BGP路径属性分类

目录 前言&#xff1a; 路径属性分类 公认必遵 公认任意 可选过渡 可选非过渡 前言&#xff1a; 在默认情况下&#xff0c;到达同一目的地&#xff0c;BGP只走单条路径&#xff0c;并不会在多条路径之间执行负载均衡。对于IGP路由协议&#xff0c;当有多条路径可以到达同…

丘一丘正则表达式

正则表达式(regular expression,regex,RE) 正则表达式是一种用来简洁表达一组字符串的表达式正则表达式是一种通用的字符串表达框架正则表达式是一种针对字符串表达“简洁”和“特征”思想的工具正则表达式可以用来判断某字符串的特征归属 正则表达式常用操作符 操作符说明实…

[vscode]将命令行参数传递给调试目标

一、简介 本文介绍了在vscode中使用cmake工具时&#xff0c;如何传递参数给编译目标的方法。 前提&#xff1a;使用vscodecmake编译C/C程序。 二、方法 在.vscode/目录下新建settings.json文件&#xff0c;并将待传底的参数写在 cmake.debugConfig里。 下面介绍了一个示例&a…

DAY14二叉树迭代遍历

二叉树前序迭代法遍历 前序遍历是中左右&#xff0c;每次先处理的是中间节点&#xff0c;那么先将根节点放入栈中&#xff0c;然后将右孩子加入栈&#xff0c;再加入左孩子。 为什么要先加入 右孩子&#xff0c;再加入左孩子呢&#xff1f; 因为这样出栈的时候才是中左右的顺…

Stable Diffusion 如何写好提示词(Prompt)

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里。 大家好&#xff0c;我是水滴~~ 本文深入探讨了如何撰写出优质的提示词&#xff0c;内容涵盖多个维度&#xff1a;提示词的多样化分类、模型应用中的经典提示词案例、提供丰富资源的提示词参考…