遇到左括号入栈,遇到右括号出栈。需要注意的是:
- 在出栈时要判断当前栈是否为空
- 可能出现左括号的数目抑一直大于右括号的情况,此时栈即使在循环结束时也不为空
32.最长有效括号
我不会做!!!
这道题目有三种解法,分别是
- 动态规划
- 辅助栈
- 正向逆向结合
我在这里主要说一下如何使用栈来解决该问题。
听完闫总的讲解,我简单地复述一遍。
首先,有效括号要符合两个条件:
- 在一个有效括号字符串中,左括号的数目必须等于右括号的数目
- 在一个有效括号字符串中,任意字符串前缀中的左括号的数目都大于等于右括号的数目。
我们在给定的字符串挑选出右括号大于等于左括号的分界点(即包含该字符,恰好右括号的个数大于左括号),假设这样的分界点共有 n n n个。我们只需要在这 n n n个分界点中任意两个之间寻找最长的有效括号匹配即可。
为什么只需要在任意两个之间寻找最长的有效括号即可?
根据便是有效括号必须满足上述第二个条件,也就是说,有效括号不会跨过分界点。
42.接雨水
我不会做!!!
方法:单调栈或动态规划。
84.柱状图中的最大矩形
我不会做!!!
有两种暴力做法:
- 枚举左右区间,求解最小高度
- 枚举高度,向左右两侧求解左右区间,左右区间满足它的高度一定小于所枚举的高度(左右区间表示的区间是一个开区间)
考虑优化,可以使用单调栈来求解左右区间。
85.最大矩形
我不会做!!!
方法:
- 预处理
matrix[i][j]左边连1的个数(包括matrix[i][j]),并将结果存放在left[i][j]中- 枚举所有以
matrix[i][j]为右下角的矩形,那么该矩形的最大宽度一定是left[i][j],left[i - 1][j]⋯ \cdots ⋯left[k][j],0 <= k <= i的最小值。优化
注意到第二步实际上就是在求解每一列(以该列的元素作为矩形的右下角)的矩形最大面积,因此我们可以按照84.柱状图中的最大矩形所使用的单调栈进行优化。
数据结构:栈
- 使用栈存储操作数,并从左到右遍历给定数组
- 遇到操作数字,入栈
- 遇到运算符,弹出栈中栈顶的两个操作数,对它们进行相应的操作,并将结果压入栈中。注意运算顺序,第一次从栈中弹出的操作数是第二个操作数,而第二次从栈中弹出的元素是第一个操作数。
整个逆波兰表达式遍历结束后,栈中只剩下一个操作数,该操作数即是逆波兰表达式的计算结果。
数据结构:栈
需要用到两个栈:
- 符号栈
op:存放+,-,(等运算符- 数据栈
num:存放所有的数字从左到右遍历整个字符串,并做如下处理:
- 若遇到空格,跳过
- 遇到数字字符,继续遍历,知道遇到非数字字符为止,把一个连续的数字取出,放入
nums中- 遇到左括号
(,放入符号栈op- 遇到右括号
),做如下操作:
- 若符号栈
op栈顶元素不为),使用用现有的nums和op一直计算,直到符号栈op栈顶元素不为)- 弹出符号栈
op栈顶元素- 遇到
+,-:要放入符号栈op中,在放入之前把栈内可以计算的数字都算掉,直到没有操作或栈顶元素为(,计算结果放入num中
进阶
请思考如下问题:如果表达式中包含*,/,%等运算优先级更高的运算符,又该如何处理?
若表达式中包含比+,-运算优先级更高的运算符,在运算符加入符号栈之前,要判断栈顶运算符和当前运算符的优先级大小。若栈顶运算符的优先级大于等于当前运算符的优先级,则使用现有的num和op进行计算,并把计算结果放入数字栈,否则不对栈顶运算符做任何操作。最后把当前运算符加入符号栈。
一些细节:
- 由于第一个数可能是负数,为了避免边界判断,常用的小技巧是向
nums添加一个0- 为了防止
()内出现的第一个字符是运算符,在遇到左括号后,需要去除多余的空格并判断第一个有效字符是否是-,如果是,则向nums添加一个0。
栈:栈是一种后进先出的数据结构,即后加入栈中的元素会优先被弹出。
队列:队列是一种先进先出的数据结构,即先加入队列中的元素会优先被弹出。
用队列实现栈的关键在于修改翻转在队列中的顺序,即若加入数据的是
abc,那么队列中数据的顺序应该是cba。一个队列自然不可能实现上述功能,为此,我们可以借助一个辅助队列来实现。具体实现过程如下:
- 假设初始时主队列
q的数据顺序是abcdefg,辅助队列为空,待加入的数据是h- 把
h加到辅助队列当中- 把主队列中的元素移到辅助队列当中,此时辅助队列中的数据顺序是
habcdefg- 把辅助队列中的数据移到主队列中
- 辅助队列重新为空,主队列中的数据顺序是
habcdefg,满足栈后进先出的特性。
算法和思路:贪心 + 单调栈
具体而言,遍历字符串
s,若s[i]字典序大于当前栈顶元素的字典序,并且栈顶元素存在于字符串s的第i个元素的后面,那么删掉栈顶元素。重复上述过程直到栈中元素为空或栈顶元素字典序小于s[i]。
还有一点需要注意,若当前元素
s[i]在栈中已经出现过,那么就跳过本轮循环。
方法:深度优先搜索 或 栈
深度优先搜索
NestedInteger中只能包含下面两部分之一:1. 数字 2. 一个列表,其中列表中的元素都是一个NestedInteger。通过分析,不难得到NestedInteger通过递归定义的,这启示我们可以使用深度优先搜索。
算法的具体步骤如下:
- 判断是否是数字,如果是,直接返回
- 递归处理字符串
s- 遇到字符
[,说明后面是一个NestedInteger。在遇到第一个[时,什么也不做,遇到第二个[,递归处理字符串s - 遇到字符
],返回结果NestedInteger - 遇到字符
,,跳过不作处理 - 遇到数字
0-9或-,提取出数字num,把num加入到当前递归层下的NestedInteger中
- 遇到字符
- 返回最后的结果
注意:
- 递归程序的接口是
NestedInteger dfs(string& s,int& idx) - 为了使代码看起来更加清晰,可以把提取数字
num的代码封装为一个函数
栈
可以用栈模拟上述思路。
每个[的出现意味着一个嵌套类型的NestedInteger的实例,每个]的出现意味着一个嵌套类型的NestedInteger的实例的结束。
遍历字符串s,算法步骤如下:
- 遇到
[,新建一个NestedInteger实例,压入栈中 - 遇到
]或,,说明一个NestedInteger实例结束,把该实例加入到栈顶元素中 - 遇到数字,把数字提取出来

232

被折叠的 条评论
为什么被折叠?



