本系列为Leetcode刷题笔记,刷题平台为Leetcode中文站, 刷题按Tag
分类。本系列题解汇总如下 (持续更新…):
本文主要是栈和队列
相关题目题解总结。
[TOC]
栈和队列
栈的顺序为后进先出,队列 的顺序为先进先出。
20. 有效的括号
题目描述
给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:1
2输入: "()"
输出: true
示例 2:1
2输入: "()[]{}"
输出: true
示例 3:1
2输入: "(]"
输出: false
示例 4:1
2输入: "([)]"
输出: false
示例 5:1
2输入: "{[]}"
输出: true
解题思路
使用栈,遍历字符串,当栈为空或者当前字符为左括号’(‘,’[‘,’{‘时或者为右括号但是栈顶字符与其不匹配,则将字符加入栈,否则栈顶字符出栈。最后判断栈是否为空。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool
"""
if not s:
return True
Dict = {')':'(', '}':'{', ']':'['}
stack = []
for c in s:
if not stack or c not in Dict or stack[-1] != Dict[c]:
stack.append(c)
else:
stack.pop()
return True if not stack else False
71. 简化路径
题目描述
以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。更多信息请参阅:Linux / Unix中的绝对路径 vs 相对路径
请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。
示例 1:1
2
3输入:"/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。
示例 2:1
2
3输入:"/../"
输出:"/"
解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。
示例 3:1
2
3输入:"/home//foo/"
输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。
示例 4:1
2输入:"/a/./b/../../c/"
输出:"/c"
示例 5:1
2输入:"/a/../../b/../c//.//"
输出:"/c"
示例 6:1
2输入:"/a//b////c/d//././/.."
输出:"/a/b/c"
解题思路
将字符串按照‘/‘分隔得到了每个文件的目录,然后遍历每个目录进行入栈或者出栈。
如果目录为空或者为当前目录’.’,则不进行任何操作;如果为’..’,表示返回上一级目录,如果栈中有上级目录,则将其弹出。
1 | class Solution(object): |
84. 柱状图中最大的矩形
题目描述
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10
解题思路
使用一个递增单调栈,栈中保存坐标,数组中坐标依次入栈,当当前坐标的值小于栈顶坐标的值,则栈顶坐标弹出,并计算弹出坐标的面积,它的右边界是当前坐标的值(因为当前坐标让它出栈),左边界是栈顶坐标(当栈为空时为-1)。
当数组遍历完成后,栈不为空,则依次弹出,计算弹出坐标的面积,右边界是数组长度,左边界是栈顶坐标(当栈为空时为-1)。
例如:[2,1,5,6,2,3]
先将2的坐标入栈,栈为[0];
元素1的坐标1入栈前比较,因为1位置的元素比栈顶(0)位置的元素小,则位置0出栈,栈为空,计算0位置的面积(1-(-1)-1)*2=2,在将1入栈,栈为[1];
坐标2的元素5大于栈顶位置元素(1),则坐标2入栈,栈为[1,2];
坐标3的元素6大于栈顶位置元素(5),则坐标3入栈,栈为[1,2,3];
坐标4的元素2小于栈顶位置元素(6),则将栈顶位置3弹出,栈为[1,2],计算3位置的面积(4-2-1)*6 = 6,此时2依然小于栈顶位置2的元素5,则栈顶位置2出栈,栈为[1],计算2位置的面积(4-1-1)*5=10;此时2大于栈顶位置元素,则2的坐标4入栈,栈为[1,4];
坐标5的元素3大于栈顶位置元素(2),坐标5入栈,栈为[1,4,5];
数组遍历完成。
此时栈不为空,依次弹出计算面积。
弹出位置5,栈为[1,4],面积为(6-4-1)*3=3;
弹出位置4,栈为[1],面积为(6-1-1)*2=8;
弹出位置1,栈为空,面积为(6-(-1)-1)*1=6;
所以最大面积为max(2,6,10,3,8,6)=10。
1 | class Solution(object): |
85. 最大矩形
题目描述
给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
示例:1
2
3
4
5
6
7
8输入:
[
["1","0","1","0","0"],
["1","0","1","1","1"],
["1","1","1","1","1"],
["1","0","0","1","0"]
]
输出: 6
解题思路
使用一个辅助数组,大小为矩阵列宽,依次以矩阵每一行为底计算最大面积,直接调用上一题的代码计算。辅助数组计算方法:初始化为0,当当前元素为1是,高度加1,为0时直接为0。
例如上例:
第一行 [1 0 1 0 0]
第二行 [2 0 2 1 1]
第三行 [3 1 3 2 2]
第四行 [4 0 0 3 0]
1 | class Solution(object): |
150. 逆波兰表达式求值
题目描述
根据逆波兰表示法,求表达式的值。
有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
- 整数除法只保留整数部分。
- 给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:1
2
3输入: ["2", "1", "+", "3", "*"]
输出: 9
解释: ((2 + 1) * 3) = 9
示例 2:1
2
3输入: ["4", "13", "5", "/", "+"]
输出: 6
解释: (4 + (13 / 5)) = 6
示例 3:1
2
3
4
5
6
7
8
9
10输入: ["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
解题思路
在python中,(-1)/2=-1,而在c语言中,(-1)/2=0。也就是c语言中,除法是向零取整,即舍弃小数点后的数。而在python中,是向下取整的。而这道题的oj是默认的c语言中的语法,所以需要在遇到’/’的时候注意一下。
1 | class Solution(object): |
155. 最小栈
题目描述
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
- push(x) — 将元素 x 推入栈中。
- pop() — 删除栈顶的元素。
- top() — 获取栈顶元素。
- getMin() — 检索栈中的最小元素。
示例:1
2
3
4
5
6
7
8MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
解题思路
1 | class MinStack(object): |
224. 基本计算器
题目描述
实现一个基本的计算器来计算一个简单的字符串表达式的值。
字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 。
示例 1:1
2输入: "1 + 1"
输出: 2
示例 2:1
2输入: " 2-1 + 2 "
输出: 3
示例 3:1
2输入: "(1+(4+5+2)-3)+(6+8)"
输出: 23
说明:
你可以假设所给定的表达式都是有效的。
请不要使用内置的库函数 eval。
解题思路
1 | class Solution(object): |
225. 用队列实现栈
题目描述
使用队列实现栈的下列操作:1
2
3
4push(x) -- 元素 x 入栈
pop() -- 移除栈顶元素
top() -- 获取栈顶元素
empty() -- 返回栈是否为空
注意:
你只能使用队列的基本操作— 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。
解题思路
使用一个队列,每次新元素进队列的时候,先把当前的数字进入队列,然后把它前面的所有的元素移到新进队的后面。
例如:
1进队列, [1] -> [1]
2进队列, [1,2] ->[2,1]
3进队列, [2,1,3] ->[3,2,1]
4进队列, [3,2,1,4] ->[4,3,2,1]
栈顶为第一个元素
1 | class MyStack(object): |
232. 用栈实现队列
题目描述
使用栈实现队列的下列操作:
push(x) — 将一个元素放入队列的尾部。
pop() — 从队列首部移除元素。
peek() — 返回队列首部的元素。
empty() — 返回队列是否为空。
示例:1
2
3
4
5
6
7MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
queue.peek(); // 返回 1
queue.pop(); // 返回 1
queue.empty(); // 返回 false
说明:
你只能使用标准的栈操作 — 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。
解题思路
1 | class MyQueue(object): |