数据结构 | 栈之单调栈

简介

单调栈,可以用来优化时间复杂度,是个利器。

定义

单调栈,顾名思义,是一个单调的栈。栈内元素一般都是无序的,如何保持栈内元素是有序的呢?接下来,我们进行分析。

单调栈分为单调递增栈和单调递减栈,通过使用单调栈我们可以访问到下一个比他大(小)的元素。

什么时候使用单调栈?
通常是一维数组,要寻找任一元素右边(左边)第一个比自己大(小)的元素,且要求 O(n) 的时间复杂度

算法

单调递增栈:从 栈底 到 栈顶 递增,栈顶大
单调递减栈:从 栈底 到 栈顶 递减,栈顶小

1. 单调递增栈

步骤

  1. 遍历数组元素,同时开辟一个新栈的空间
  2. 如果当前栈为空,或者当前数组元素的值 > 栈顶元素:
    那么将当前数组元素压栈
  3. 如果当前数组元素的值 < 栈顶元素:
    那么将栈顶元素弹出,直至当前数组元素的值 > 栈顶元素 或者 栈为空。

图解可参见:leetcode单调栈的应用系列之概念篇(python版)

作用

  1. 从上面输出结果来看,如果从左往右遍历数组,可以获取到比当前index位置的元素的右边第一个大的元素。我们可以想象一下,如果数组从右往左遍历,那么可以获取到比当前index位置的元素的左边第一个大的元素。
  2. 一般对于我们来说,利用的是栈的特性,而栈是先进后出的,因此,从栈的角度来看,从左往右遍历:
    当栈内元素出栈时,新数组元素是出栈元素向右找第一个比其小的元素
    当栈内元素出栈后,新栈顶元素是出栈元素向左找第一个比其小的元素

python程序

功能:当前项向左找第一个比自己小的位置 —— 从左向右维护一个单调递增栈

def nextGreaterElement_04(nums: list):
    length = len(nums)
    res, stack = [-1] * length, []

    for i in range(length):
        while stack and stack[-1] >= nums[i]:
            stack.pop()
        if stack:
            res[i] = stack[-1]
        stack.append(nums[i])

    return res

程序来自:面试刷题必会:单调栈python模板套路(附用法例题详解)

2. 单调递减栈

单调递减栈与单调递增栈相反,即栈内元素保持递减顺序。

作用

  1. 从上面输出结果来看,如果从左往右遍历数组,可以获取到比当前index位置的元素的右边第一小的元素。我们可以想象一下,如果数组从右往左遍历,那么可以获取到比当前index位置的元素的左边第一小的元素。
  2. 从栈的角度来看,与递增栈相反,从左往右遍历的话,
    当栈内元素出栈时,新数组元素是出栈元素向右找第一个比其大的元素
    当栈内元素出栈后,新栈顶元素是出栈元素向左找第一个比其大的元素

python程序

功能:当前项向左找第一个比自己大的位置 —— 从左向右维护一个单调递减栈

def nextGreaterElement_03(nums: list):
    length = len(nums)
    res, stack = [-1] * length, []

    for i in range(length):
        while stack and stack[-1] <= nums[i]:
            stack.pop()
        if stack:
            res[i] = stack[-1]
        stack.append(nums[i])

    return res

猜你喜欢

转载自blog.csdn.net/lovetaozibaby/article/details/123276683