Leetcode——单调栈的认识及运用(下一个更大元素 II等)

对于栈的认识一开始我只停留在先进先出,对于它的运用我并没有过多的思考,知道这两天的刷到才知道我也知道一个概念,那么这个先进先出有什么可以运用,现在的理解是单调递增或者单调递减,可以与栈顶元素比较,比如是单调递增的栈,如果当前元素比栈顶元素小,也就是说是整个栈元素的最小值,就会将栈顶元素弹出,当前元素为栈顶元素,以此类推。对于这道题,首先要思考我们为什么要用单调栈,是用单调递增还是递减,题目是求的是循环数组的第一个比它大的值,也就是说当前元素比栈顶元素大就行,

为什么要用单调栈呢?

考虑比较次数,比如对于数组【5,4,3,9】那么也就是说【5,4,3】的第一个比它的元素肯定是9,那么我们还要迭代计算,确实时间复杂度高,那么如果我把【5,4,3】这样存起来那么只要遇到比元素3大,进行栈运算,比较栈顶元素更换栈顶元素

是递增还是递减?

那么必不可能是递增,如果栈是5,6,7,8这时候出现9,结果就会是[9,9,9,9],可是答案是[6,7,8,9],所以肯定是单调递减栈.可以通过举例子去判定用递增还是递减

怎么实现循环数组?

这道题一般循环两次就可以了,也就是遍历数组长度的2呗,再通过使用**取模运算 %**可以把下标 ii映射到数组 长度的 0 - N 内。
在这里插入图片描述
采用while一直向下比较,直到遇到比当前元素大的元素

单调栈遇到比当前元素大的两种情况

第一种

在这里插入图片描述

第二种

在这里插入图片描述

代码思想

建立「单调递减栈」,并对原数组遍历一次:

  • 如果栈为空,则把当前元素放入栈内;
  • 如果栈不为空,则需要判断当前元素和栈顶元素的大小:
    • 如果当前元素比栈顶元素大:说明当前元素是前面一些元素的「下一个更大元素」,则逐个弹出栈顶元素,直到当前元素比栈顶元素小为止。
    • 如果当前元素比栈顶元素小:说明当前元素的「下一个更大元素」与栈顶元素相同,则把当前元素入栈。
class Solution(object):
    def nextGreaterElements(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        N = len(nums)
        res = [-1] * N
        stack = []
        for i in range(N * 2):
            while stack and nums[stack[-1]] < nums[i % N]:
                res[stack.pop()] = nums[i % N]
            stack.append(i % N)
        return res

例题
1673. 找出最具竞争力的子序列
739. 每日温度
84. 柱状图中最大的矩形


1047删除字符中的所有相邻重复项
这道题太给力了完全利用栈的优势
参考动图便于理解

class Solution:
    def removeDuplicates(self, S: str) -> str:
        stack = []
        for i in S:
            if stack and stack[-1]== i:
                stack.pop(-1)
            else:
                stack.append(i)
        return "".join(stack)

用栈实现递归

224,j基本计算机
参考大佬
一个表达式分为三部分:左边表达式①,运算符③, 右边表达式②
当我们在计算一个表达式的时候,需要先计算左边表达式①,然后需要把①的结果和运算符③保存起来,再需要计算右边表达式②,最后计算①和②的运算。这个操作就是递归!!

递归的程序可以用「栈」来模拟:栈为了保存左边表达式①的计算结果和运算符③,在计算右边表达式③的结果之后,从栈中取出运算符③和①的结果,再进行计算整个表达式的结果。

代码思想

操作的步骤是:

  • 如果当前是数字,那么更新计算当前数字;
  • 如果当前是操作符+或者-,那么需要更新计算当前计算的结果 res,并把当前数字 num 设为0,sign 设为正负,重新开始;
  • 如果当前是 ( ,那么说明遇到了右边的表达式,而后面的小括号里的内容需要优先计算,所以要把res,sign 进栈,更新 res 和 sign 为新的开始;
  • 如果当前是 ),那么说明右边的表达式结束,即当前括号里的内容已经计算完毕,所以要把之前的结果出栈,然后计算整个式子的结果;
  • 最后,当所有数字结束的时候,需要把最后的一个 num 也更新到 res 中。
class Solution(object):
    def calculate(self, s):
        stack = []
        #结果
        res = 0
        #记录正负,1为正,-1为负
        sign = 1
        #记录当前数字
        num = 0
        for i in s:
            # 先判断是否为数字
            if i.isdigit():
                #如果数字是一位数以上,比如100,得读三次
                num = num *10 + int(i)
            elif i== '+' or i == '-':
                #改变res结果
                res += sign*num
                #清空读取数据的num,便于下一次读取
                num = 0
                #重新更正符号状态
                sign = 1 if i == '+' else  -1
            elif i == '(':
                #记录括号前的符号,决定这个括号结果的正负,-(5+4)或者+(5+4),先记录之前的结果再记录符号
                stack.append(res)
                stack.append(sign)
                res = 0
                #必须重新修改符号状态,如果括号前面之前是负的,不修改会影响后面的计算
                sign = 1
            elif i == ')':
                res += sign*num
                num = 0
                res *= stack.pop()
                res += stack.pop()
        #如果题目没有括号,’1+1‘,那么只能通过这一步进行相加减
        res += sign *num
        return res
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值