每日温度 单调栈
请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
示例 3:
输入: temperatures = [30,60,90]
输出: [1,1,0]
(下面都是分析,要直接看代码请直接拉到最底下!!)
思路:
直接说思路吧,我们需要用单调栈去做这道题。这道题要求的是求出一个数组当中,每一个数的下一个较大的值在哪个位置。不管是下一个较大值还是下一个较小值,不管是求绝对位置(具体下标)还是相对位置(离它的距离),这都是一个单调栈就可以解决的问题。
以后我们在有类似的需求:求下一个较大值、下一个较小值时,就直接用单调栈即可。
什么是单调栈?就是一个只允许我们存放按顺序上升或下降的数的栈。比如有一个递减单调栈,每次我们添加元素,都要判断栈顶元素是不是比当前元素大,满足条件我们才能添加;如果不满足条件,就把栈顶元素弹出pop(),再比较新的栈顶元素和要添加元素的大小,直到满足条件我们才能添加新元素。若一直不满足条件,我们甚至不惜把栈全置空再添加元素,以便绝对遵守递减的性质。
就算直到单调栈的性质,那它这一特性又和我们的题目有啥关系呢——单调栈是我们得到题目结果过程当中的的一个辅助数据结构。利用单调栈的性质,再按照特定的顺序遍历给定数组,在操作单调栈过程中将中间结果添加进结果数组就可以得到结果。
具体怎么导入,怎么操作,可以去看,但是看了马上就会忘记。四个月前我把“为啥这样就能利用单调栈求出结果”的代码原理和逻辑在脑海里过得明明白白,但现在我再整理这个的时候,又感觉十分陌生和抽象了。
人的大脑是真的无法永久记忆的,曾经的我误以为LeetCode题目刷多了可以变得聪明、变得睿智,但实际上,刷题除了保持短期内对题目的熟悉和对套路的熟练之外,没有别的长期作用。所以并不强求去理解原理,我们唯一要记住的就是它的应用场景——求下一个较大、较小值;以及它的代码实现框架、套路就好了。因为我们的重点就是把题做出来,把题做出来只需要两步:知道要用什么方法,知道这个方法怎么用。
单调栈模板:
def 模板函数(nums):
lenth = len(nums)
stack=[]#定义单调栈,存储的是下标
res = [0]*lenth#定义存储结果的列表
for i in range(lenth-1,-1,-1):
while(stack and nums[stack[-1]]<=nums[i]):#判断需要弹出条件
stack.pop()
#pop完后 栈顶元素可以给res了
res[i]=stack[-1] if stack else 0#如果stack没有值,给缺省值0
stack.append(i)#添加入单调栈
return res
下面这一段话不需要完全理解,能看就看,看不懂也不要纠结,无所谓的,我写这段的目的就是辅助我们理解并记住模板——因为只要记住一半的逻辑就很有助于我们记忆实现方式:
(这段话,随缘看)简单描述一下这个模板的逻辑:我们从后往前地遍历给定数组,准备把当前值对应的下标加入单调栈。之前已经说过了,单调栈添加元素,要满足它对应的升上/下降性质,所以我们要拿当前值和栈顶元素(是个下标)在数组中对应的值进行比较,从而先进行栈的pop()操作。弹出元素之后,不要着急添加这个新下标,先在中间加入我们存放结果的语句:将此时的栈顶元素赋给结果列表,若此时栈顶元素为空,则赋我们给定的缺省值0(也可以是其他任何值)。最后添加我们的新下标。
好了,不管有没有看懂上面这段话,我们一定要做的就是记住这个模板的实现方式和使用方式。
先说一下这个模板函数的作用:
传入数组nums,得到与nums对应的下一个较大值的下标。
比如对于[3,4,1,2,1,4],可以得到[1, 0, 3, 5, 5, 0]。其中0就是缺省值。
上面这句话的两处红色部分,是可以灵活修改的。
一、如果我们要得到下一个较小值的下标,只需将 while(stack and nums[stack[-1]]<=nums[i]):
改成
while(stack and nums[stack[-1]]>=nums[i]):
就可以得到下一个较小值的下标。
比如对于[3,4,1,2,1,4],可以得到[2, 2, 0, 4, 0, 0]。
二、如果我们要得到下一个较大值的距离。(这个距离是指与当前位置的距离,也正是“每日温度”这一题的要求)只需将 res[i]=stack[-1] if stack else 0
改成
res[i]=stack[-1]-i if stack else 0
比如对于[3,4,1,2,1,4],可以得到[1, 0, 1, 2, 1, 0]。
三、若要得到下一个较小值的距离。
则两处同时改,就好了:
首先将 while(stack and nums[stack[-1]]<=nums[i]):
改成
while(stack and nums[stack[-1]]>=nums[i]):
再将 res[i]=stack[-1] if stack else 0
改成
res[i]=stack[-1]-i if stack else 0.
回到这一题,题目要求的就是下一个较大值的距离。其实就是第二种改法。直接套模板:
代码:
class Solution(object):
def dailyTemperatures(self, T):
stack=[]
lenth = len(T)
res = [0]*lenth
for i in range(lenth-1,-1,-1):
while stack and T[stack[-1]]<=T[i]:#第一处修改,写成<=
stack.pop()
res[i] = stack[-1]-i if stack else 0#第二处修改,加上-i
stack.append(i)
return res
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了