Leetcode——栈经典题目

20.有效的括号

遇到左括号入栈,遇到右括号出栈。需要注意的是:

  1. 在出栈时要判断当前栈是否为空
  2. 可能出现左括号的数目抑一直大于右括号的情况,此时栈即使在循环结束时也不为空

32.最长有效括号
我不会做!!!

这道题目有三种解法,分别是

  1. 动态规划
  2. 辅助栈
  3. 正向逆向结合

我在这里主要说一下如何使用栈来解决该问题。

听完闫总的讲解,我简单地复述一遍。
首先,有效括号要符合两个条件

  1. 在一个有效括号字符串中,左括号的数目必须等于右括号的数目
  2. 在一个有效括号字符串中,任意字符串前缀中的左括号的数目都大于等于右括号的数目。

我们在给定的字符串挑选出右括号大于等于左括号的分界点(即包含该字符,恰好右括号的个数大于左括号),假设这样的分界点共有 n n n个。我们只需要在这 n n n个分界点中任意两个之间寻找最长的有效括号匹配即可。

为什么只需要在任意两个之间寻找最长的有效括号即可?
根据便是有效括号必须满足上述第二个条件,也就是说,有效括号不会跨过分界点。

42.接雨水
我不会做!!!

方法:单调栈动态规划

84.柱状图中的最大矩形
我不会做!!!

有两种暴力做法:

  1. 枚举左右区间,求解最小高度
  2. 枚举高度,向左右两侧求解左右区间,左右区间满足它的高度一定小于所枚举的高度(左右区间表示的区间是一个开区间)

考虑优化,可以使用单调栈来求解左右区间。

85.最大矩形
我不会做!!!

方法

  1. 预处理matrix[i][j]左边连1的个数(包括matrix[i][j]),并将结果存放在left[i][j]
  2. 枚举所有以matrix[i][j]为右下角的矩形,那么该矩形的最大宽度一定是left[i][j],left[i - 1][j] ⋯ \cdots left[k][j],0 <= k <= i的最小值。

优化
注意到第二步实际上就是在求解每一列(以该列的元素作为矩形的右下角)的矩形最大面积,因此我们可以按照84.柱状图中的最大矩形所使用的单调栈进行优化。

150.逆波兰表达式求值

数据结构:栈

  1. 使用栈存储操作数,并从左到右遍历给定数组
  2. 遇到操作数字,入栈
  3. 遇到运算符,弹出栈中栈顶的两个操作数,对它们进行相应的操作,并将结果压入栈中。注意运算顺序,第一次从栈中弹出的操作数是第二个操作数,而第二次从栈中弹出的元素是第一个操作数。

整个逆波兰表达式遍历结束后,栈中只剩下一个操作数,该操作数即是逆波兰表达式的计算结果。

224.基本计算器

数据结构:栈

需要用到两个栈:

  • 符号栈op:存放+,-,(等运算符
  • 数据栈num:存放所有的数字

从左到右遍历整个字符串,并做如下处理:

  1. 若遇到空格,跳过
  2. 遇到数字字符,继续遍历,知道遇到非数字字符为止,把一个连续的数字取出,放入nums
  3. 遇到左括号(,放入符号栈op
  4. 遇到右括号),做如下操作:
    1. 若符号栈op栈顶元素不为),使用用现有的numsop一直计算,直到符号栈op栈顶元素不为)
    2. 弹出符号栈op栈顶元素
  5. 遇到+,-:要放入符号栈op中,在放入之前把栈内可以计算的数字都算掉,直到没有操作或栈顶元素为(,计算结果放入num

进阶
请思考如下问题:如果表达式中包含*,/,%等运算优先级更高的运算符,又该如何处理?
   若表达式中包含比+,-运算优先级更高的运算符,在运算符加入符号栈之前,要判断栈顶运算符和当前运算符的优先级大小。若栈顶运算符的优先级大于等于当前运算符的优先级,则使用现有的numop进行计算,并把计算结果放入数字栈,否则不对栈顶运算符做任何操作。最后把当前运算符加入符号栈。

一些细节

  1. 由于第一个数可能是负数,为了避免边界判断,常用的小技巧是向nums添加一个0
  2. 为了防止()内出现的第一个字符是运算符,在遇到左括号后,需要去除多余的空格并判断第一个有效字符是否是-,如果是,则向nums添加一个0。

225.用队列实现栈

:栈是一种后进先出的数据结构,即后加入栈中的元素会优先被弹出。
队列:队列是一种先进先出的数据结构,即先加入队列中的元素会优先被弹出。

用队列实现栈的关键在于修改翻转在队列中的顺序,即若加入数据的是abc,那么队列中数据的顺序应该是cba

一个队列自然不可能实现上述功能,为此,我们可以借助一个辅助队列来实现。具体实现过程如下:

  1. 假设初始时主队列q的数据顺序是abcdefg,辅助队列为空,待加入的数据是h
  2. h加到辅助队列当中
  3. 把主队列中的元素移到辅助队列当中,此时辅助队列中的数据顺序是habcdefg
  4. 把辅助队列中的数据移到主队列中
  5. 辅助队列重新为空,主队列中的数据顺序是habcdefg,满足栈后进先出的特性。

316.去除重复字母

算法和思路:贪心 + 单调栈

具体而言,遍历字符串s,若s[i]字典序大于当前栈顶元素的字典序,并且栈顶元素存在于字符串s的第i个元素的后面,那么删掉栈顶元素。重复上述过程直到栈中元素为空或栈顶元素字典序小于s[i]

还有一点需要注意,若当前元素s[i]在栈中已经出现过,那么就跳过本轮循环。


385.迷你语法分析器

方法:深度优先搜索 或 栈

深度优先搜索

NestedInteger中只能包含下面两部分之一:1. 数字 2. 一个列表,其中列表中的元素都是一个NestedInteger。通过分析,不难得到NestedInteger通过递归定义的,这启示我们可以使用深度优先搜索。

算法的具体步骤如下:

  1. 判断是否是数字,如果是,直接返回
  2. 递归处理字符串s
    1. 遇到字符[,说明后面是一个NestedInteger。在遇到第一个[时,什么也不做,遇到第二个[,递归处理字符串s
    2. 遇到字符],返回结果NestedInteger
    3. 遇到字符,,跳过不作处理
    4. 遇到数字0-9-,提取出数字num,把num加入到当前递归层下的NestedInteger
  3. 返回最后的结果

注意:

  1. 递归程序的接口是NestedInteger dfs(string& s,int& idx)
  2. 为了使代码看起来更加清晰,可以把提取数字num的代码封装为一个函数

可以用栈模拟上述思路。
每个[的出现意味着一个嵌套类型的NestedInteger的实例,每个]的出现意味着一个嵌套类型的NestedInteger的实例的结束。

遍历字符串s,算法步骤如下:

  1. 遇到[,新建一个NestedInteger实例,压入栈中
  2. 遇到],,说明一个NestedInteger实例结束,把该实例加入到栈顶元素中
  3. 遇到数字,把数字提取出来

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值