什么时候用单调栈?
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了,时间复杂度为O(n)。
单调栈作用:就是用一个栈来记录我们遍历过的元素
单调栈存放的内容:单调栈里只需要存放元素的下标i就可以了,如果需要使用对应的元素,直接通过索引就可以获取。
如果求一个元素右边第一个更大元素,单调栈就是递增的(从栈头到栈底的顺序),如果求一个元素右边第一个更小元素,单调栈就是递减的(从栈头到栈底的顺序)。
LeetCode739题 每日温度
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
res = [0] * len(temperatures)
stack = []
for i in range(len(temperatures)):
# 若当前温度高于栈顶元素,则持续出栈,进行结果更新,栈顶到栈底是递增的
while stack and temperatures[i] > temperatures[stack[-1]]:
res[stack[-1]] = i - stack[-1]
stack.pop()
# 将当前温度入栈
stack.append(i)
return res
LeetCode496题 下一个更大元素
class Solution:
def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
res = [-1] * len(nums1)
# nums1元素值-索引映射
d = dict()
for i in range(len(nums1)):
d[nums1[i]] = i
stack = []
for i in range(len(nums2)):
while stack and nums2[i] > nums2[stack[-1]]:
res[d[nums2[stack[-1]]]] = nums2[i]
stack.pop()
# nums1中元素才会入栈
if nums2[i] in d:
stack.append(i)
return res
LeetCode503题 下一个更大元素II
class Solution:
def nextGreaterElements(self, nums: List[int]) -> List[int]:
res = [-1] * len(nums)
stack = []
for i in range(len(nums)):
while stack and nums[i] > nums[stack[-1]]:
res[stack[-1]] = nums[i]
stack.pop()
stack.append(i)
for i in range(len(nums)):
while stack and nums[i] > nums[stack[-1]]:
res[stack[-1]] = nums[i]
stack.pop()
# 第二次遍历不需要将元素i入栈
# 因为第一次遍历后不在栈中的元素已经找到了答案
return res
LeetCode42题 接雨水
本质在找每个元素左右两边第一个比它大的元素
class Solution:
def trap(self, height: List[int]) -> int:
res = 0
stack = []
for i in range(len(height)):
while stack and height[i] > height[stack[-1]]:
# 此时对于索引stack[-1],右边第一个比它大的位置为i,左边第一个比它大的位置为stack[-2]
if len(stack) > 1:
# 以stack[-1]为底的水池高度
h = min(height[i], height[stack[-2]]) - height[stack[-1]]
# 以stack[-1]为底的水池宽度
w = i - stack[-2] - 1
res += h * w
stack.pop()
stack.append(i)
return res
LeetCode84题 柱状图中最大的矩形
本质在找每个元素左右两边第一个比它小的元素
class Solution:
def largestRectangleArea(self, heights: List[int]) -> int:
res = 0
# heights两边加0元素,可以解决不包含边界元素问题
heights = [0] + heights + [0]
stack = []
for i in range(len(heights)):
while stack and heights[i] < heights[stack[-1]]:
if len(stack) > 1:
# 计算以heights[stack[-1]]为高的矩形的最大面积
# 主要在寻找heights[stack[-1]]左右两边的第一个比它小的元素
tmp = (i - stack[-2] - 1) * heights[stack[-1]]
res = max(res, tmp)
stack.pop()
stack.append(i)
return res