Algorithm-MonoStack

date
Oct 27, 2023
slug
algorithm-monoStack
status
Published
tags
algorithm
type
Post
https://twitter.com/tangdahe
summary
monotonic stack

739 每日温度

使用单调栈进行求解

单调栈:通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。时间复杂度为 O(n)。
例如本题其实就是找找到一个元素右边第一个比自己大的元素,此时就应该想到用单调栈了。
那么单调栈的原理是什么呢?为什么时间复杂度是 O(n) 就可以找到每一个元素的右边第一个比它大的元素位置呢?
单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优点是整个数组只需要遍历一次。
更直白来说,就是用一个栈来记录我们遍历过的元素,因为我们遍历数组的时候,我们不知道之前都遍历了哪些元素,以至于遍历一个元素找不到是不是之前遍历过一个更小的,所以我们需要用一个容器(这里用单调栈)来记录我们遍历过的元素。
在使用单调栈的时候首先要明确如下几点:
  1. 单调栈里存放的元素是什么?
单调栈里只需要存放元素的下标 i 就可以了,如果需要使用对应的元素,直接 T[i] 就可以获取。
  1. 单调栈里元素是递增呢? 还是递减呢?
注意以下讲解中,顺序的描述为 从栈头到栈底的顺序,因为单纯的说从左到右或者从前到后,不说栈头朝哪个方向的话,大家一定比较懵。
这里我们要使用递增循序(再强调一下是指从栈头到栈底的顺序),因为只有递增的时候,栈里要加入一个元素 i 的时候,才知道栈顶元素在数组中右面第一个比栈顶元素大的元素是 i。
即:如果求一个元素右边第一个更大元素,单调栈就是递增的,如果求一个元素右边第一个更小元素,单调栈就是递减的。
使用单调栈主要有三个判断条件。
  • 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
  • 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
  • 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况
 
思路:
  1. 如果当前栈为空,将下标 i 直接入栈
  1. 如果当前栈不为空,取出栈顶下标,如果其元素低于当前元素的值,更新对应下标的结果值,循环上述操作,直到栈顶下标元素大于当前元素,当前元素入栈
  1. 遍历结束,栈中所有下标的元素相当于没有遇到更大的值,放弃更新,该题默认为 0
notion image
 
 

496 下一个更大元素1

nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。
给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。
对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。
返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。
notion image
根据 739 的解答,可以将其封装为一个工具包(有改动增加 map),我们只需要将 nums2 中的所有元素的下一个更大的值求出来,然后根据 nums1 中的值寻找即可,为了一次性找到 nums1 中的元素在结果集中的位置,我们需要记录一个 map 来进行标记位置,能够快速找到目标值
平均时间复杂度是 O(n + m),其中 n 和 m 分别是 nums2nums1 的长度,符合题中的进阶要求

503 下一个更大元素2

同 496 解题思路一致,只不过针对循环数组我们需要走两边

42 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
notion image
todo:
 

© Craig Hart 2021 - 2024