一、单调栈解决的问题
单调栈用途不太广泛,只处理一类典型的问题,比如「下一个更大元素」,「上一个更小元素」等。
二、单调栈的算法思想
单调栈的算法思想是基于栈的后进先出(LIFO)特性,并结合单调性(单调递增或单调递减)来高效地解决“下一个最大或最小”问题。以下是单调栈的核心思想和为什么它可以解决这类问题的详细解释:
核心思想:
-
栈的后进先出特性:栈是一种后进先出的数据结构,这意味着最后进入栈的元素会最先被弹出。
-
单调性维护:单调栈在入栈时,会确保栈内元素按照某种单调性排列(单调递增或单调递减)。如果新元素破坏了这种单调性,则需要将不符合要求的栈顶元素全部弹出【内部while语句】,直到新元素能够保持栈的单调性。
为什么单调栈可以解决下一个最大或最小问题:
-
逆序进栈(保证下一个):栈内元素是当前元素的后面的元素,栈顶是紧接当前元素的下一位元素;
-
单调性保证(while语句):单调栈维护,保证每一个元素进栈前,都清理了栈内不符合单调性的元素, 栈顶元素是当前元素下一个最大或最小值的元素;
-
时间效率:单调栈可以在O(n)的时间复杂度内解决问题,因为它每个元素最多只会被压入和弹出栈一次。
三、算法的python模板
from labuladong:
from typing import List
def nextGreaterElement(nums: List[int]) -> List[int]:
stack = []
res = [-1] * len(nums)
for i in range(len(nums)-1, -1, -1):
# 倒着入栈:栈内是当前元素后面的元素,栈顶是紧接当前元素的元素
# 保持单调性:清理当前元素入栈后不满足单调性的元素,保证“当前轮元素进栈后仍保持单调性”
while stack and stack[-1] <= nums[i]:
stack.pop()
# 这个位置:栈为空 或 stack[-1] > nums[i], 是单调栈
# 更新结果:栈顶不为空即为下一个目标值
if stack: res[i] = stack[-1]
# 当前轮元素入栈:每个元素都会进栈
stack.append(nums[i])
# 新元素进栈,保持单调性,单调栈进入下一轮循环
return res
nums = [2,1,2,4,3]
print(nextGreaterElement(nums))