单调栈简介

0. 简介

最近在自己编写一些小的算法的时候,深感自己的算法过于臃肿。碰巧Datawhale在新的一期组队学习中组织了数据结构与算法的课程学习。于是就参加了,再次感谢Datawhale~~

首先跟大家分享一下两个自己感觉比较好的学习资料,一个是 算法通关手册 ,也是Datawhale在本次组队学习中的学习资料;一个是B站上的视频 【北京大学】数据结构与算法Python版(完整版),老师讲的特别棒(也难得有Python版的数据结构课程,哈哈~)。

1. 单调栈简介

单调栈 是一种特殊的堆栈的形式。它在栈的「先进后出」规则基础上,要求「从栈顶到栈底的元素是单调递增(或者单调递减)」。其中满足从栈顶到栈底的元素是单调递增的栈,叫做 单调递增栈 。满足从栈顶到栈底的元素是单调递减的栈,叫做 单调递减栈

对于 单调递增栈 ,只有比栈顶元素小的元素才能直接进栈,否则需要先将栈中比当前元素小的元素出栈,再将当前元素入栈。假设当前进栈元素为 x,如果栈顶元素大于 x,则直接入栈。否则从栈顶开始遍历栈中元素,把小于 x 或者等于 x 的元素弹出栈,直到遇到一个大于 x 的元素为止,然后再把 x 压入栈中。

单调栈可以在时间复杂度为 O ( n ) O(n) O(n) 的情况下,求解出某个元素左边或者右边第一个比它大或者小的元素。所以单调栈一般用于解决一下几种问题:

  • 寻找左侧第一个比当前元素大的元素

从左到右遍历元素,构造单调递增栈(从栈顶到栈底递增):一个元素左侧第一个比它大的元素就是将其「插入单调递增栈」时的栈顶元素。如果插入时的栈为空,则说明左侧不存在比当前元素大的元素。

  • 寻找左侧第一个比当前元素小的元素

从左到右遍历元素,构造单调递减栈(从栈顶到栈底递减):一个元素左侧第一个比它小的元素就是将其「插入单调递减栈」时的栈顶元素。如果插入时的栈为空,则说明左侧不存在比当前元素小的元素。

  • 寻找右侧第一个比当前元素大的元素

从左到右遍历元素,构造单调递增栈(从栈顶到栈底递增):一个元素右侧第一个比它大的元素就是将其「弹出单调递增栈」时即将插入的元素。如果该元素没有被弹出栈,则说明右侧不存在比当前元素大的元素。

  • 寻找右侧第一个比当前元素小的元素

从左到右遍历元素,构造单调递减栈(从栈顶到栈底递减):一个元素右侧第一个比它小的元素就是将其「弹出单调递减栈」时即将插入的元素。如果该元素没有被弹出栈,则说明右侧不存在比当前元素小的元素。

算法通关手册 中给出了单调递增栈和单调递减栈的 Python 模板:

## 单调递增
def monotoneIncreasingStack(nums):
	stack = []
	for num in nums:
		while stack and num >= stack[-1]:
			stack.pop()
		stack.append(num)

## 单调递减
def monotoneDecreasingStack(nums):
	stack = []
	for num in nums:
		while stack and num <= stack[-1]:
			stack.pop()
		stack.append(num)

2.单调栈的应用

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

题目要求:

给定一个列表 temperatures,每一个位置对应每天的气温。
要求:输出一个列表,列表上每个位置代表如果要观测到更高的气温,至少需要等待的天数。如果之后的气温不再升高,则用 0 来代替。

题目的意思实际上就是给定一个数组,每个位置上有整数值。对于每个位置,在该位置右侧找到第一个比当前元素更大的元素。求「该元素」与「右侧第一个比当前元素更大的元素」之间的距离,将所有距离保存为数组返回结果。

class Solution:
    def dailyTemperatures(self, T: List[int]) -> List[int]:
        n = len(T)
        stack = []
        ans = [0 for _ in range(n)]
        for i in range(n):
            while stack and T[i] > T[stack[-1]]:
                index = stack.pop()
                ans[index] = (i-index)
            stack.append(i)
        return ans
  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值