Leetcode901-股票价格跨度

一、前言

本题基于leetcode901股票价格趋势这道题,说一下通过java解决的一些方法。并且解释一下笔者写这道题之前的想法和一些自己遇到的错误。需要注意的是,该题最多调用 next 方法 10^4 次,一般出现该提示说明需要注意时间复杂度。

二、解决思路

①栈排序(存在超出时间限制问题)

其实笔者做这道题之前并不知道单调栈这一东西,第一时间想到的是很像之前做过的和栈相关的一道题–栈排序,毕竟都是类似按照某一顺序对栈元素进行排序。需要借用辅助栈,而考虑到它需要计算的是连续天数,不是一个简单的排序。
拿这道题给的示例输入来说:
在这里插入图片描述
思路就是如果是空栈,那么我们直接放就好。
而当不是空栈时,此时通过price和栈顶元素的差值区分情况:
①小于0:
说明price要小,那么我们直接入栈,然后由于此时栈肯定没有比price更小的元素,所以只有它自己,return 1即可
②大于等于0:
说明此时price要大于栈顶元素,由于它要的是最大连续日数(从今天开始往回数,包括今天),那么我必须得保持入栈的一个顺序,否则就不是连续的,而是一个比当前price要小的所有天数这样一个结果
那么怎样处理呢,我们可以先将该price入辅助栈,然后再从栈顶遍历,将小于等于当前price的栈元素弹出push到辅助栈中。此时记录辅助栈的size就是我们要返回的最大连续天数,最后再将辅助栈一次push到我们的主栈中即可
我这边画一个图:
在这里插入图片描述
如上图,第一次入栈70这个元素时,比栈顶元素60要大,将price=70入辅助栈,然后遍历主栈栈顶,将小于等于70的元素弹出栈然后push进辅助栈,此时记录辅助栈size为2,然后将辅助栈元素全部弹出并且推入主栈,最后返回size即可。且这样不会修改我主栈元素的原本顺序,就是按照next元素的顺序进行排序的,就也顺便解决了连续这个问题。
同理,后面入75如下图所示:
在这里插入图片描述
代码如下:

class StockSpanner {private Stack<Integer> stockStack;private Stack<Integer> diffStack;public StockSpanner() {stockStack = new Stack<>();diffStack = new Stack<>();}public int next(int price) {if (stockStack.isEmpty()) {stockStack.push(price);return 1;} else {int diff = price - stockStack.peek();if (diff < 0) {stockStack.push(price);return 1;} else {diffStack.push(price);while (!stockStack.isEmpty() && stockStack.peek() <= price) {diffStack.push(stockStack.pop());}int res = diffStack.size();while (!diffStack.isEmpty()) {stockStack.push(diffStack.pop());}return res;}}}
}

好像这样思路确实没什么问题,运行发现超出时间限制o(╥﹏╥)o:
在这里插入图片描述

虽说时间复杂度是O(n),可是这样的操作确实还是非常繁琐的,且还需要借助辅助栈且最后主栈的元素量是Next()的调用次数,无效或者其实用不上的元素根本没有pop出栈,导致浪费了很多空间。
所以也就有了后面一种方法–单调栈,该方法不再需要辅助栈,且不会浪费额外空间。

②单调栈

我们将每一个股票价格想象成java的一个对象,它拥有它的id,拥有它的价格,我们可以使用一个int[]去承装他们,int[0]装id,int[1]装价格。
然后我们可以想象下,我们需要比今日股票要小于等于的天数,是否就是将这些对象给按照一个单调递减的顺序排序,如果放入的元素比上一个元素要小,此时结果就是当前放入元素的下标id和上一个元素下标的差值。如果要大,此时不符合单调递减,那么我需要将比它小的元素全部抹去,让我们承装对象的结构始终符合单调递减,此时结果是当前当如元素的下标id和抹去后的它的上一个元素下标id的差值。
为了方便我们后续程序少一些空栈之类的判断,我们初始化的时候可以先push进一个id为0,价格是Integer.MAX的元素,这样到时候我们出栈也不用担心会导致空栈
而对于next方法,首先是下标,这个很好理解,我们每次调用next方法时,id++即可,很像我们数据库的ID自增策略。由于我们需要的是小于或等于今天价格的最大连续日数,所以是一个单调递减栈,如果要插入的price大于栈顶元素,此时将单调栈的元素依次弹出,并且此时将当前price对应的下标减去出栈后的栈顶元素的下标,这个下标差就是我们需要返回的结果。然后再将当前元素入栈即可然后返回下标差即可。
仍然拿示例1举例:
当我插入100-80-60,由于每次插入都比栈顶元素要小,而当插入70时,此时比栈顶元素60要大,从栈顶开始遍历,一直到栈顶元素大于price为止,此时出栈完后栈顶是id=2,price=80这个元素,然后记录res=4-2=2,然后将price=70,id=4这个元素入栈。
在这里插入图片描述
放入60,75同理:
在这里插入图片描述
代码如下:

class StockSpanner {private Deque<int[]> stockStack;private int id;public StockSpanner() {stockStack = new ArrayDeque<>();stockStack.push(new int[]{0,Integer.MAX_VALUE});id = 0;}public int next(int price) {id ++;while (price >= stockStack.peek()[1]){stockStack.pop();}int ret = id - stockStack.peek()[0];stockStack.push(new int[]{id, price});return ret;}
}

在这里插入图片描述

三、栈排序和单调栈的区别

那么其实栈排序和单调栈是有明显区别的,这里做一个总结:

单调栈单调栈是一种特殊的栈结构,其插入时保证栈内元素的单调性。通常用于解决数组中下一个更大或下一个更小元素的问题。例如我们可以见我们力扣496下一个更大元素 I这道题,单调栈需要维护一个单调递增或单调递减的栈顶元素序列,每当新元素插入时,都需要判断该元素与栈顶元素的大小关系,不断弹出栈顶元素直到满足单调性。

栈排序:栈排序是对栈内元素进行递增或递减排序的一种思路。通常使用额外的栈来辅助排序。将原始栈的元素依次弹出,插入到辅助栈中的正确位置,最后将辅助栈中的元素重新压回原始栈中,从而实现了栈排序。需要注意的是,仅使用原始栈是无法实现栈排序的,因为栈的弹出顺序一旦改变就无法恢复

总体来说,单调栈和栈排序都是基于栈实现的常用算法思路,但其应用场景和实现方法不同。单调栈通常用于解决比较问题,需要维护栈内元素的单调性;而栈排序则是对栈内元素的排序,需要额外借助辅助栈实现

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记录本地部署Stable-diffusion所依赖的repositories和一些插件

今天按照其他文章的步骤拉取好了https://github.com/AUTOMATIC1111/stable-diffusion-webui后&#xff0c;点击webui-user.bat后发现&#xff0c;repositories和models还得慢慢拉取&#xff0c;好吧&#xff0c;GitHub Desktop&#xff0c;启动&#xff01; BLIP: https://git…

【论文极速读】EMT——评估多模态LLM中的灾难性遗忘问题

【论文极速读】EMT——评估多模态LLM中的灾难性遗忘问题 FesianXu 20231001 at Baidu Search Team 前言 论文[1]报告了多模态LLM中遇到的灾难性遗忘问题&#xff0c;并且提出了一种评估其程度的方法EMT&#xff0c;本文简要介绍&#xff0c;希望对读者有所帮助。如有谬误请见谅…

从哈希表到红黑树:探讨 epoll 是如何管理事件的?

一、引言 在计算机领域&#xff0c;事件通知是一种重要的机制&#xff0c;用于监视和响应各种事件&#xff0c;例如网络连接、文件IO、定时器等。随着计算机应用变得越来越复杂&#xff0c;对于高性能事件通知机制的需求也越来越迫切。传统的事件通知机制可能存在效率低下的问…

[架构之路-232]:目标系统 - 纵向分层 - 操作系统 - 数据存储:文件系统存储方法汇总

目录 前言&#xff1a; 一、文件系统存储方法基本原理和常见应用案例&#xff1a; 二、Windows FAT文件系统 2.1 概述 三、Linux EXT文件系统 3.1 基本原理 3.2 索引节点表&#xff08;Inode Table&#xff09; 3.2.1 索引节点表层次结构 3.2.2 间接索引表的大小和表项…

Java卷上天,可以转行干什么?

小刚是某名企里的一位有5年经验的高级Java开发工程师&#xff0c;每天沉重的的工作让他疲惫不堪&#xff0c;让他萌生出想换工作的心理&#xff0c;但是转行其他工作他又不清楚该找什么样的工作 因为JAVA 这几年的更新实在是太太太……快了&#xff0c;JAVA 8 都还没用多久&am…

鄙视测试,理解测试,成为测试

首先&#xff0c;其实题主的问题还是很实诚的&#xff0c;我刚开始做测试的时候其实也是这个心态&#xff0c;想转开发&#xff0c;也学习了很多的语言&#xff0c;个人觉得这是职业危机感的表现&#xff0c;挺好的&#xff0c;也相信题主不管去做开发和测试都会去不断的学习和…

SAP从入门到放弃系列之QM目录类别、代码组、选择集维护

目录 一、概念相关内容1.1 目录类别1.2 代码组和代码1.3 选择集和选择集代码 二、系统操作相关内容 一、概念相关内容 1.1 目录类别 目录类别是对定性数据的一种归纳&#xff0c;描述了业务的主题。根据PA的教材中表述&#xff0c;目录类型 0 - 9 和 A - O 由 SAP 定义&#…

深入浅出的介绍一下虚拟机VMware Workstation——part1

目录 VMware Workstation说明VMware Workstation的主要特点VMware Workstation安装VMware Workstation卸载 VMware Workstation说明 1、 虚拟机的软件在市面上有很多&#xff0c;目前功能强大且比较主流的虚拟机软件首选VMware 2、VMware是一个虚拟PC的软件&#xff0c;可以在…

什么是全员生产维护TPM?

在当今竞争激烈的市场环境中&#xff0c;企业不仅需要提高生产效率&#xff0c;同时也需要降低成本以保持竞争力。全员生产维护&#xff08;Total Productive Maintenance&#xff0c;TPM&#xff09;作为一种先进的生产管理方法&#xff0c;为企业提供了一种有效的方式来实现这…

【小沐学Python】Python实现Web图表功能(Dash)

文章目录 1、简介2、安装3、功能示例3.1 Hello World3.2 连接到数据3.3 可视化数据3.4 控件和回调3.5 设置应用的样式3.5.1 HTML and CSS3.5.2 Dash Design Kit (DDK)3.5.3 Dash Bootstrap Components3.5.4 Dash Mantine Components 4、更多示例4.1 Basic Dashboard4.2 Using C…

光伏发电预测(LSTM、CNN_LSTM和XGBoost回归模型,Python代码)

运行效果&#xff1a;光伏发电预测&#xff08;LSTM、CNN_LSTM和XGBoost回归模型&#xff0c;Python代码&#xff09;_哔哩哔哩_bilibili 运行环境库的版本 光伏太阳能电池通过互连形成光伏模块&#xff0c;以捕捉太阳光并将太阳能转化为电能。因此&#xff0c;当光伏模块暴露…

OpenCV4(C++) —— 图像数据类型转换和颜色模型转换

文章目录 一、图像数据类型转换二、颜色模型转换三、通道的分离和融合 一、图像数据类型转换 OpenCV中使用imread读取一张彩色图像时&#xff0c;默认采用的是BGR通道和整数类型(0-255&#xff0c;CV_8U)。 在某些情况下&#xff0c;会将整数类型(0-255)转换为浮点类型(0-1)&a…