leetcode单调栈的应用系列之概念篇(python版)

写在前面

最近博主在leetcode上刷题时发现一个新的数据结构:单调栈,可以用来优化时间复杂度,是个利器。楼主在这里做一个单调栈系列总结。

什么是单调栈

单调栈的定义

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

单调栈的分类

从数学上,我们知道,单调一般有单调递增和单调递减。那么对于单调栈来说,一般有单调递增栈和单调递减栈。

单调递增栈

单调递增栈,顾名思义,栈内元素保持递增顺序。我们可以实现一下:

单调栈实现基本思想

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

# coding: utf-8
def get_increasing_stack(nums):
    """
    给定一个数组,输出为单调递增栈
    :param nums:
    :return:
    """
    stack = []
    for num_index in range(len(nums)):
        if not stack or nums[num_index] > stack[-1]:
            stack.append(nums[num_index])
        else:
            if nums[num_index] < stack[-1]:
                while stack and nums[num_index] < stack[-1]:
                    stack.pop(-1)
            stack.append(nums[num_index])
    return stack


if __name__ == '__main__':
    nums = [2, 1, 5, 6, 2, 3]
    result = get_increasing_stack(nums)
    print(result)  # 输出为[1, 2, 3]
单调递增栈的作用

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

举个例子说明一下,仍然按上面的例子进行举例:
nums = [2, 1, 5, 6, 2, 3]
单调递增栈的说明

单调递减栈

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

# coding: utf-8
def get_decreasing_stack(nums):
    stack = []
    for num_index in range(len(nums)):
        if not stack or nums[num_index] < stack[-1]:
            stack.append(nums[num_index])
        else:
            while stack and nums[num_index] > stack[-1]:
                    stack.pop(-1)
            stack.append(nums[num_index])
    return stack


if __name__ == '__main__':
    nums = [2, 1, 5, 6, 2, 3]
    result = get_decreasing_stack(nums)
    print(result) # 输出为[6, 3]
单调递减栈的作用

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

举个例子说明一下,仍然按上面的例子进行举例:
nums = [2, 1, 5, 6, 2, 3]:

在这里插入图片描述

记忆技巧

有些朋友会说,这绕来绕去我都晕了,到底是个啥情况?
我们只需要记住针对栈的就好了,对比的对象都是出栈元素,假设遍历方向为从左往右。

如果是递增栈的话,栈内元素肯定是递增的,而栈又是先进后出的,故而即将入栈的新元素的位置肯定是在pop出来的元素后面,也就是右边; *栈顶元素的位置肯定是在pop出来的元素前面,也就是左边。*又因为栈内元素递增,pop出来的元素呢肯定是因为新元素比pop出来的元素小才导致被pop的,那么栈顶元素就应该是pop出来元素的左边第一小的元素了,即将新入栈的元素呢就应该是pop出来元素向右找的第一小的元素。

这一篇主要是对单调栈做一个简单剖析,接下来一篇,对单调栈的应用【主要是leetcode上题目】进行剖析。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值