leecode-栈小结(1)

本文总结了LeetCode中与栈相关的几道经典题目,包括有效的括号、简化路径、柱状图中最大的矩形、每日温度、二叉树的中序遍历、锯齿形层次遍历、逆波兰表达式求值以及最小栈的解题思路,涉及栈的基本操作和应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、基本语法

  • 获取Stack对象
Stack<Character> stack=new Stack<>();
  • 入栈
 stack.push(ch);
  • 出栈,栈为空时会抛出异常
char ch=stack.pop();
  • 获取栈顶元素但不出栈,栈为空时会抛出异常
char ch=s.peek();
  • 判断栈是否为空
stack.isEmpty()

二、题目

leecode-20 有效的括号(简单)

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:简单模拟,获取一个栈对象,依次扫描字符串,碰到左括号入栈( ‘(’,’{’,’[’ ),碰到右括号( ‘)’,’}’,’]’ ),如果栈为空(说明当前这个右括号,没有相应的左括号与之匹配),或者此时栈顶元素不是当前右括号对应的左括号,返回false,当遍历完整个字符串,如果此时栈不为空,则说明,字符串中有多余的左括号没有被右括号匹配,返回false。否则,返回true。

leecode-71 简化路径(中等)

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs 相对路径

请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。

示例 1:

输入:"/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。
示例 2:

输入:"/…/"
输出:"/"
解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。
示例 3:

输入:"/home//foo/"
输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。
示例 4:

输入:"/a/./b/…/…/c/"
输出:"/c"
示例 5:

输入:"/a/…/…/b/…/c//.//"
输出:"/c"
示例 6:

输入:"/a//b////c/d//././/…"
输出:"/a/b/c"

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/simplify-path
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:可以使用java String中的split方法,以字符‘/‘为分隔符,将原始字符串中的字符分开,然后依次扫描这些被分开的字符串片段,获取一个栈对象来记录路径,让这些对象依次入栈。
如果当前字符串为’.‘和空,则不做任何操作。
如果当前字符串为’..’,此时指示要向上级返回,如果此时栈如果为空,则说明,到当前字符,当前路径表示根路径,则不做任何操作,如果此时栈不为空,则让栈弹出一个元素来模拟路径中的指向上级目录。
其他情况,让字符串入栈。
此时栈中元素,从头到尾的字符串以‘/’拼接,即为所求。这里要注意的一个细节就是,如果当前栈没有任何元素,最后的答案要输出‘/’表示根目录,而不是空字符串

leecode-84. 柱状图中最大的矩形(困难)

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

在这里插入图片描述

以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。

在这里插入图片描述

图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

示例:

输入: [2,1,5,6,2,3]
输出: 10

解题思路:
思路一:暴力,暴力的办法可以分别枚举,所有可能的矩形的宽,然后乘以相对应的高,在所有的面积中求一个最大值。同时也可以枚举所有矩形的高,乘以相对应的宽来求一个最大值,时间复杂度为O(n^2)。
思路二:单调栈
在我们枚举高的时候,一种可能的算法,就是从头到尾枚举每个点,然后以该点的高来构建满足条件的矩形,此时需要以该点为中心,依次向两边扩展,直到碰到左右两边第一个比当前点高度低的点,然后利用右边界来减去左边界来获取所构建矩形的宽,依次枚举,取所有矩形面积的最大值。平均的算法时间复杂度为O(n^2)。
细想如果有高度序列[1,2,4,5,3,5,7],当计算了高度为5的左边界后,下一次要计算的就是高度为3节点的左边界,因为5>3,所以我们知道,3的左边界,也就是左边比3小的第一个节点一定在5的左边界的左边(因为5的左边界代表比5小的第一个节点,那么在这节点右边的节点一定是大于5的,所以肯定是大于3的),这样就造成了重复计算。故该算法可以优化。

考虑使用栈。假设有7个节点的高度序列为[1,2,4,5,3,5,7],定义一个leftBorder数组,为第一个元素的左边界初始化为[-1,],此时让1的下标0进栈:
Stack:0
LeftBorder:[-1,…]
对于第二个元素因为2>1,故第二个元素的左边界即为0,此时让2的下标1进栈,此时:
Stack:0,1
LeftBorder:[-1,0,…]
对于第三个元素和第四个元素同理,依次让他们的下标进栈,此时更新栈和左边界数组为:
Stack:0,1,2,3
LeftBorder:[-1,0,1,2,…]
当遇见第五个节点时,其高度为3,因为3小于此时栈顶下标对应的高度5,此时说明,在栈顶下标对应节点的左边还可能存在比高度比3大的节点,故此时将栈顶弹出栈,然后比较当前的栈顶下标对应高度4,大于3,继续弹出栈顶元素,直到栈为空或者栈顶下标对应的高度小于3,此时当前栈顶元素即为当前节点的左边界。此时栈变为:
Stack:0,1
LeftBorder:[-1,0,1,2,1,…]
当下一个节点的高度大于3时,3的下标就是他的左边界,当下一个节点的高度小于3时,此时的栈顶元素是3的左边界,因为他的节点高度比3小,那么他的左边界一定在3的左边界的右边,这就说明,我们前面弹出栈的操作,不仅不会得到错误的答案,反而优化了上述所说的重复计算的问题。
同理,每个节点的右边界也可以得出。
左右边界都有,那么答案就已经解得了。

leecode-739. 每日温度(中等)

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

解题思路:单调栈。

leecode-94. 二叉树的中序遍历(中等)

给定一个二叉树,返回它的中序 遍历。

示例:

输入: [1,null,2,3]
1

2
/
3

输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
解题思路:直接递归,使用栈的算法还没看,相似的还有二叉树的前序,后序遍历。

leecode-103. 二叉树的锯齿形层次遍历(中等)

给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

例如:
给定二叉树 [3,9,20,null,null,15,7],

3

/
9 20
/
15 7
返回锯齿形层次遍历如下:

[
[3],
[20,9],
[15,7]
]
解题思路:使用BFS遍历,然后再加一个标志位来控制左右输出顺序。

leecode-150. 逆波兰表达式求值(中等)

根据 逆波兰表示法,求表达式的值。

有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

说明:

整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

示例 1:

输入: [“2”, “1”, “+”, “3”, “*”]
输出: 9
解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:

输入: [“4”, “13”, “5”, “/”, “+”]
输出: 6
解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:

输入: [“10”, “6”, “9”, “3”, “+”, “-11”, “", “/”, "”, “17”, “+”, “5”, “+”]
输出: 22
解释:
该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

逆波兰表达式:

逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。

平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:

去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。
解题思路:模拟,将数字入栈,碰到一个操作数时,弹出两个数字计算结果,然后将该数字压入栈中。

leecode-155. 最小栈(简单)

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

示例:

输入:
[“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.

解题思路:使用两个栈,第一个栈用来支持栈的push和pop操作,另外一个栈来记录到当前栈顶元素,栈中的最小值。
就以题目中描述的例子来说,第一次-2入栈。
Stack:-2
MinStack:-2(当前栈中的最小值),-2
0入栈
Stack:-2,0
MinStack:-2,-2,-2,0
-3入栈
Stack:-2,0,-3
MinStack:-2,-2,-2,0,-3,-3
由以上可知,要获取当前栈中的最小值时,只需取MinStack中的倒数第二个元素,当要执行出栈操作时,比如,在当前状态下进行出栈操作,此时Stack弹出一个元素,MinStack弹出两个元素
Stack:-2,0
MinStack:-2,-2,-2,0
此时栈中的最小元素依旧是MinStack的倒数第二个元素。
第二种思路,类似的,直接使用一个上述的MinStack就可以了,入栈时,同时加入一个截止目前为止的最小值和当前元素,出栈时,同时弹出两个元素。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值