目录
- 励志:🔔半身浸江,全身如林,所谓万丈深渊,下去也是前程万里。我启程了,你呢?
- 一、LIFO栈
- 1.逆序链表
- 题:剑指 Offer 06. 从尾到头打印链表
- 解:
- 题:206. 反转链表
- 解:
- 2.括号匹配
- 题:20. 有效的括号
- 解:
- 题:32. 最长有效括号
- 解:
- 3.回文链表
- 题:剑指 Offer II 027. 回文链表
- 解:
- 题:234. 回文链表
- 题:面试题 02.06. 回文链表
- 4.表达式求值
- 题:682. 棒球比赛
- 解:
- 5.双栈判等
- 题:844. 比较含退格的字符串
- 解:
- 二、单调栈
- 1.最小栈
- 题:155. 最小栈
- 解:
- 题:面试题 03.02. 栈的最小值
- 题:剑指 Offer 30. 包含min函数的栈
- 2.栈模拟队列
- 题:232. 用栈实现队列
- 解:
- 题:剑指 Offer 09. 用两个栈实现队列
- 题:面试题 03.04. 化栈为队
- 3.辅助栈
- 题:1352. 最后 K 个数的乘积
- 解:
- 4.最大矩形
- 题:84. 柱状图中最大的矩形
- 解:
- 剑指 Offer II 039. 直方图最大矩形面积
- 题:85. 最大矩形
励志:🔔半身浸江,全身如林,所谓万丈深渊,下去也是前程万里。我启程了,你呢?
一、LIFO栈
1.逆序链表
题:剑指 Offer 06. 从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
限制:
解:
解题思路:辅助栈
AC代码:
- 时间复杂度:O(N),入栈、出栈使用O(N)时间
- 空间复杂度:O(N),辅助栈和数组使用额外的O(N)空间
解题思路:递归
AC代码:
- 时间复杂度:O(N)
- 空间复杂度:O(N)
题:206. 反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
示例 2:
示例 3:
提示:
进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
解:
解题思路:三人行模板
AC代码:
- 时间复杂度:O(N),遍历链表,N为链表长度
- 空间复杂度:O(1),指针消耗常数空间O(1)
解题思路:递归
AC代码:
- 时间复杂度:O(N)
- 空间复杂度:O(1)
2.括号匹配
题:20. 有效的括号
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
示例 1:
示例 2:
示例 3:
示例 4:
示例 5:
提示:
解:
解题思路:辅助栈
AC代码:
- 时间复杂度:O(N),N为字符串长度。
- 空间复杂度:O(N +C),N为栈长,C为字符集。
题:32. 最长有效括号
给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
示例 2:
示例 3:
提示:
解:
📖 解题思路:动态规划
- 最长 => 动态规划
- dp[i]表示以i结尾的最长有效括号
- 情况分类讨论:
AC代码:
- 时间复杂度:O(N),N为字符串长度,遍历整个字符串一次,求出dp数组
- 空间复杂度:O(N),N为数组dp的大小
解题思路:栈
AC代码:
- 时间复杂度:O(N)
- 空间复杂度:O(N)
3.回文链表
题:剑指 Offer II 027. 回文链表
给定一个链表的 头节点 head ,请判断其是否为回文链表。
如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。
示例 1:
示例 2:
提示:
进阶:能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
解:
解题思路:
- 找中点
- 反转后半
- 比对
- 还原(可有可无)
AC代码:
- 时间复杂度:O(N),N为链表长度
- 空间复杂度:O(1),指针消耗常数空间
题:234. 回文链表
题:面试题 02.06. 回文链表
4.表达式求值
题:682. 棒球比赛
你现在是一场采用特殊赛制棒球比赛的记录员。这场比赛由若干回合组成,过去几回合的得分可能会影响以后几回合的得分。
比赛开始时,记录是空白的。你会得到一个记录操作的字符串列表 ops,其中 ops[i] 是你需要记录的第 i 项操作,ops 遵循下述规则:
- 整数 x - 表示本回合新获得分数 x
- “+” - 表示本回合新获得的得分是前两次得分的总和。题目数据保证记录此操作时前面总是存在两个有效的分数。
- “D” - 表示本回合新获得的得分是前一次得分的两倍。题目数据保证记录此操作时前面总是存在一个有效的分数。
- “C” - 表示前一次得分无效,将其从记录中移除。题目数据保证记录此操作时前面总是存在一个有效的分数。
请你返回记录中所有得分的总和。
示例 1:
示例 2:
示例 3:
提示:
- 1 <= ops.length <= 1000
- ops[i] 为 “C”、“D”、"+",或者一个表示整数的字符串。整数范围是 [-3 * 104, 3 * 104]
- 对于 “+” 操作,题目数据保证记录此操作时前面总是存在两个有效的分数
- 对于 “C” 和 “D” 操作,题目数据保证记录此操作时前面总是存在一个有效的分数
解:
解题思路:栈
AC代码:
- 时间复杂度:O(N),N是字符串ops的长度。
- 空间复杂度:O(N),用于存储stack的空间。
5.双栈判等
题:844. 比较含退格的字符串
给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,请你判断二者是否相等。# 代表退格字符。
如果相等,返回 true ;否则,返回 false 。
注意:如果对空文本输入退格字符,文本继续为空。
示例 1:
示例 2:
示例 3:
示例 4:
提示:
- 1 <= s.length, t.length <= 200
- s 和 t 只含有小写字母以及字符 ‘#’
解:
解题思路:栈
AC代码:
- 时间复杂度:O(N)
- 空间复杂度:O(N)
解题思路:双指针
AC代码:
- 时间复杂度:O(N)
- 空间复杂度:O(1)
二、单调栈
1.最小栈
题:155. 最小栈
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
- push(x) —— 将元素 x 推入栈中。
- pop() —— 删除栈顶的元素。
- top() —— 获取栈顶元素。
- getMin() —— 检索栈中的最小元素。
示例:
提示:
解:
解题思路:递减栈
AC代码:
另解:先将Integer自动拆箱为int,再比较
- 时间复杂度:O(1)
- 空间复杂度:O(N) 两个栈的大小
题:面试题 03.02. 栈的最小值
题:剑指 Offer 30. 包含min函数的栈
2.栈模拟队列
题:232. 用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
- 你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
进阶:
- 你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。
示例:
提示:
解:
解题思路:双栈模拟
AC代码:
- 时间复杂度:O(1)
- 空间复杂度:O(N),两个栈in,out所耗空间
题:剑指 Offer 09. 用两个栈实现队列
题:面试题 03.04. 化栈为队
3.辅助栈
题:1352. 最后 K 个数的乘积
请你实现一个「数字乘积类」ProductOfNumbers,要求支持下述两种方法:
1.add(int num)
- 将数字 num 添加到当前数字列表的最后面。
2.getProduct(int k)
- 返回当前数字列表中,最后 k 个数字的乘积。
- 你可以假设当前列表中始终 至少 包含 k 个数字。
题目数据保证:任何时候,任一连续数字序列的乘积都在 32-bit 整数范围内,不会溢出。
示例:
提示:
解:
解题思路:前缀积
AC代码:
- 时间复杂度:O(1)
- 空间复杂度:O(N),额外的一个辅助列表
4.最大矩形
题:84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例 1:
示例 2:
提示:
- 1 <= heights.length <=105
- 0 <= heights[i] <= 104
解:
解题思路:单调栈
单调栈模板:
AC代码:
- 时间复杂度:O(N)
- 空间复杂度:O(N),newHeights数组、stack栈额外占用N空间
剑指 Offer II 039. 直方图最大矩形面积
题:85. 最大矩形