这篇文章是leetcode
刷题系列的第5
部分——队列和栈。这里把有代表性的题目发出来,共计22
道。主要涉及BFS
算法、DFS
算法、单调栈以及单调队列技巧的应用。
leetcode
刷题系列其它文章组织如下:
1
. 数组
2
. 链表
3
. 字符串
4
. 二叉树
5
. 队列和栈
6
. 动态规划
7
. 数据结构设计
8
. 刷题小知识点
1660. Correct a Binary Tree
你有一棵二叉树,这棵二叉树有个小问题,其中有且只有一个无效节点,它的右子节点错误地指向了与其在同一层且在其右侧的一个其他节点。
给定一棵这样的问题二叉树的根节点
root
,将该无效节点及其所有子节点移除(不移除被错误指向的节点),然后返回新二叉树的根结点。示例:
1
2
3 输入: root = [8,3,1,7,null,9,4,2,null,null,null,5,6], fromNode = 7, toNode = 4
输出: [8,3,1,null,null,9,4,null,null,5,6]
解释: 值为 7 的节点是无效的,所以移除这个节点及其子节点 2。
1 | // 借助层序遍历的思想 |
394. Decode String
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为:
k[encoded_string]
,表示其中方括号内部的encoded_string
正好重复k
次。注意k
保证为正整数。你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数
k
,例如不会出现像3a
或2[4]
的输入。Constraints:
1 <= s.size() <= 30
s
consists of lowercase English letters, digits, and square brackets'[]'
.s
is guaranteed to be a valid input.- All the integers in
s
are in the range[1, 300]
.Example 1:
1
2 Input: s = "3[a]2[bc]"
Output: "aaabcbc"Example 2:
1
2 Input: s = "2[abc]3[cd]ef"
Output: "abcabccdcdcdef"
1 | void repeatString(string& str, int count) |
752. Open the Lock
你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有
10
个数字:'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
。每个拨轮可以自由旋转:例如把'9'
变为'0'
,'0'
变为'9'
。每次旋转都只能旋转一个拨轮的一位数字。锁的初始数字为
'0000'
,一个代表四个拨轮的数字的字符串。列表
deadends
包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。字符串
target
代表可以解锁的数字,你需要给出最小的旋转次数,如果无论如何不能解锁,返回-1
。Example 1:
1
2
3
4
5
6 Input: deadends = ["0201","0101","0102","1212","2002"], target = "0202"
Output: 6
Explanation:
A sequence of valid moves would be "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202".
Note that a sequence like "0000" -> "0001" -> "0002" -> "0102" -> "0202" would be invalid,
because the wheels of the lock become stuck after the display becomes the dead end "0102".Example 2:
1
2
3
4
5 Input: deadends = ["8888"], target = "0009"
Output: 1
Explanation:
We can turn the last wheel in reverse to move from "0000" -> "0009".
1 | // 宽度优先遍历 BFS 通常用来解决最小(距离)、最短(路径)、最少(步数)等问题 |
37. Sudoku Solver
编写一个程序,通过填充空格来解决数独问题。
一个数独的解法需遵循如下规则:
- 数字
1-9
在每一行只能出现一次。- 数字
1-9
在每一列只能出现一次。- 数字
1-9
在每一个以粗实线分隔的3x3
宫内只能出现一次。空白格用'.'
表示。
一个数独 红色为答案
1 | // 这是深度优先搜索算法应用的典型题目 |
279. Perfect Squares
给定正整数
n
,找到若干个完全平方数(比如1, 4, 9, 16, ...
)使得它们的和等于n
。你需要让组成和的完全平方数的个数最少。给你一个整数
n
,返回和为n
的完全平方数的最少数量。Example 1:
1
2
3 Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.Example 2:
1
2
3 Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.
1 | // DP 递推式: numSquares(n) = min(numSquares(n - k)) + 1 |
155. Min Stack
设计一个支持
push
,pop
,top
操作,并能在常数时间内检索到最小元素的栈。
push(x)
—— 将元素x
推入栈中。
pop()
—— 删除栈顶的元素。
top()
—— 获取栈顶元素。
getMin()
—— 检索栈中的最小元素。
1 | class MinStack |
739. Daily Temperatures
请根据每日气温列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用
0
来代替。例如,给定一个列表
temperatures = [73, 74, 75, 71, 69, 72, 76, 73]
,你的输出应该是[1, 1, 4, 2, 1, 1, 0, 0]
。
1 | // 这题本质上就是找到当前元素的下一个比它大的元素 |
496. Next Greater Element I
给你两个没有重复元素的数组
nums1
和nums2
,其中nums1
是nums2
的子集。请你找出
nums1
中每个元素在nums2
中的下一个比其大的值。
nums1
中数字x
的下一个更大元素是指x
在nums2
中对应位置的右边的第一个比x
大的元素。如果不存在,对应位置输出-1
。Example:
1
2
3
4
5
6 Input: nums1 = [4,1,2], nums2 = [1,3,4,2]
Output: [-1,3,-1]
Explanation:
For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1.
For number 1 in the first array, the next greater number for it in the second array is 3.
For number 2 in the first array, there is no next greater number for it in the second array, so output -1.
1 | // 直接套用单调栈的模板 |
503. Next Greater Element II
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字
x
的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出-1
。Example:
1
2
3 >Input: [1,2,1]
>Output: [2,-1,2]
>Explanation: The first 1's next greater number is 2; The number 2 can't find next greater number; The second 1's next greater number needs to search circularly, which is also 2.
1 | // 这里和 I 题的区别是, 数组可以循环 |
556. Next Greater Element III
给你一个正整数
n
,请你找出符合条件的最小整数,其由重新排列n
中存在的每位数字组成,并且其值大于n
。如果不存在这样的正整数,则返回-1
。Example 1:
1
2 Input: n = 320241
Output: 320412Example 2:
1
2 Input: n = 321
Output: -1
1 | // 首先要想到的是先把数字转成字符串, 方便处理 |
133. Clone Graph
给你无向连通图中一个节点的引用,请你返回该图的深拷贝(克隆)。
图中的每个节点都包含它的值
val
(int
)和其邻居的列表list[Node]
。
1
2
3
4
5
6
7
8
9
10
11 // Definition for a Node.
struct Node
{
int val;
vector<Node *> neighbors;
Node(int _val)
{
val = _val;
neighbors = vector<Node *>();
}
};Example:
1
2
3
4
5
6
7 Input: adjList = [[2,4],[1,3],[2,4],[1,3]]
Output: [[2,4],[1,3],[2,4],[1,3]]
Explanation: There are 4 nodes in the graph.
1st node (val = 1)'s neighbors are 2nd node (val = 2) and 4th node (val = 4).
2nd node (val = 2)'s neighbors are 1st node (val = 1) and 3rd node (val = 3).
3rd node (val = 3)'s neighbors are 2nd node (val = 2) and 4th node (val = 4).
4th node (val = 4)'s neighbors are 1st node (val = 1) and 3rd node (val = 3).
1 | // 直接深度优先搜索即可 |
494. Target Sum
给定一个非负整数数组,
a1, a2, ..., an
和一个目标数S
。现在你有两个符号+
和-
。对于数组中的任意一个整数,你都可以从+
或-
中选择一个符号添加在前面。返回可以使最终数组和为目标数
S
的所有添加符号的方法数。Example:
1
2
3
4
5
6
7
8
9
10
11 Input: nums is [1, 1, 1, 1, 1], S is 3.
Output: 5
Explanation:
-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3
There are 5 ways to assign symbols to make the sum of nums be target 3.
1 | // 先上暴力搜索 (dfs) 穷举所有添加方法的结果 |
232. Implement Queue using Stacks
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作:
实现
MyQueue
类:
void push(int x)
:将元素x推到队列的末尾;
int pop()
:从队列的开头移除并返回元素;
int peek()
:返回队列开头的元素;
bool empty()
:如果队列为空,返回true
;否则,返回false
。
1 | // 如上图, 将两个栈这样放 |
225. Implement Stack using Queues
请你仅使用两个队列实现一个后入先出的栈,并支持普通队列的全部四种操作。
实现
MyStack
类:
void push(int x)
:将元素x
压入栈顶;
int pop()
:移除并返回栈顶元素;
int top()
:返回栈顶元素;
bool empty()
:如果栈是空的,返回true
;否则,返回false
。
1 | // 队列实现栈 |
200. Number of Islands
给定一个
m x n
字符栅格网格,该栅格网格表示'1'
(土地)和'0'
(水)的地图,请返回岛的数量。一个岛屿被水包围,是通过水平或垂直连接相邻的土地而形成的。 您可以假设网格的所有四个边缘都被水包围。
Constraints:
m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j]
is'0'
or'1'
Example 1:
1
2
3
4
5
6
7 Input: grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
Output: 1Example 2:
1
2
3
4
5
6
7 Input: grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
Output: 3
1 | // 思想是 |
694. Number of Distinct Islands
给定一个非空
01
二维数组表示的网格,一个岛屿由四连通(上、下、左、右四个方向)的1
组成,你可以认为网格的四周被海水包围。请你计算这个网格中共有多少个形状不同的岛屿。两个岛屿被认为是相同的,当且仅当一个岛屿可以通过平移变换(不可以旋转、翻转)和另一个岛屿重合。
示例 1:
1
2
3
4
5 11000
11000
00011
00011
给定上图,返回结果 1 。示例 2:
1
2
3
4
5 11011
10000
00001
11011
给定上图,返回结果 3 。注意:
11
1和
1
11
是不同的岛屿,因为我们不考虑旋转、翻转操作。
1 | int x = 0, y = 0; |
1254. Number of Closed Islands
有一个二维矩阵
grid
,每个位置要么是陆地(记号为0
)要么是水域(记号为1
)。我们从一块陆地出发,每次可以往上下左右
4
个方向相邻区域走,能走到的所有陆地区域,我们将其称为一座「岛屿」。如果一座岛屿完全由水域包围,即陆地边缘上下左右所有相邻区域都是水域,那么我们将其称为 「封闭岛屿」。
请返回封闭岛屿的数目。
Example 1:
1
2
3
4 Input: grid = [[1,1,1,1,1,1,1,0],[1,0,0,0,0,1,1,0],[1,0,1,0,1,1,1,0],[1,0,0,0,0,1,0,1],[1,1,1,1,1,1,1,0]]
Output: 2
Explanation:
Islands in gray are closed because they are completely surrounded by water (group of 1s).Example 2:
1
2 Input: grid = [[0,0,1,0,0],[0,1,0,1,0],[0,1,1,1,0]]
Output: 1
1 | // 注意这题 1 代表水域而 0 代表陆地 |
695. Max Area of Island
给定一个包含了一些
0
和1
的非 空二维数组grid
。一个岛屿是由一些相邻的
1
(代表土地) 构成的组合,这里的「相邻」要求两个1
必须在水平或者竖直方向上相邻。你可以假设grid
的四个边缘都被0
(代表水)包围着。找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为
0
)Example 1:
1
2
3
4
5
6
7
8
9
10 [[0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,1,1,0,1,0,0,0,0,0,0,0,0],
[0,1,0,0,1,1,0,0,1,0,1,0,0],
[0,1,0,0,1,1,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0]]
Given the above grid, return `6`. Note the answer is not 11, because the island must be connected 4-directionally.Example 2:
1
2
3 [[0,0,0,0,0,0,0,0]]
Given the above grid, return `0`.
1 | // dfs |
733. Flood Fill
有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在
0
到65535
之间。给你一个坐标
(sr, sc)
表示图像渲染开始的像素值(行 ,列)和一个新的颜色值newColor
,让你重新上色这幅图像。为了完成上色工作,从初始坐标开始,记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。
最后返回经过上色渲染后的图像。
Example:
1
2
3
4
5
6
7
8
9 Input:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
Output: [[2,2,2],[2,2,0],[2,0,1]]
Explanation:
From the center of the image (with position (sr, sc) = (1, 1)), all pixels connected
by a path of the same color as the starting pixel are colored with the new color.
Note the bottom corner is not colored 2, because it is not 4-directionally connected
to the starting pixel.
1 | // 和前面那个岛屿数量 I 的题思路差不多 |
542. 01 Matrix
给定一个由
0
和1
组成的矩阵,找出每个元素到最近的0
的距离。两个相邻元素间的距离为
1
。矩阵中的元素只在四个方向上相邻:上、下、左、右。Example 1:
1
2
3
4
5
6
7
8
9 >Input:
>[[0,0,0],
>[0,1,0],
>[0,0,0]]
>Output:
>[[0,0,0],
>[0,1,0],
>[0,0,0]]Example 2:
1
2
3
4
5
6
7
8
9 >Input:
>[[0,0,0],
>[0,1,0],
>[1,1,1]]
>Output:
>[[0,0,0],
>[0,1,0],
>[1,2,1]]
1 | // 因为要寻找 [最近] 距离, 所以显然使用 BFS |
841. Keys and Rooms
有
N
个房间,开始时你位于0
号房间。每个房间有不同的号码:0,1,2,...,N-1
,并且房间里可能有一些钥匙能使你进入下一个房间。在形式上,对于每个房间
i
都有一个钥匙列表rooms[i]
,每个钥匙rooms[i][j]
由[0,1,...,N-1]
中的一个整数表示,其中N = rooms.length
。 钥匙rooms[i][j] = v
可以打开编号为v
的房间。最初,除
0
号房间外的其余所有房间都被锁住。你可以自由地在房间之间来回走动。
如果能进入每个房间返回
true
,否则返回false
。Note:
1 <= rooms.length <= 1000
0 <= rooms[i].length <= 1000
- The number of keys in all rooms combined is at most
3000
.Example 1:
1
2
3
4
5
6
7 Input: [[1],[2],[3],[]]
Output: true
Explanation:
We start in room 0, and pick up key 1.
We then go to room 1, and pick up key 2.
We then go to room 2, and pick up key 3.
We then go to room 3. Since we were able to go to every room, we return true.Example 2:
1
2
3 Input: [[1,3],[3,0,1],[2],[0]]
Output: false
Explanation: We can't enter the room with number 2.
1 | // 因为最多就 1000 个房间 |