今天复习利用栈与队列的特性解决问题。
LeetCode 20. 有效的括号
有效的括号中,嵌套在最内层的右括号会与最近的左侧左括号匹配,根据栈后入先出的特性,可以把从左到右遍历到的左括号暂存到栈中,遇到右括号时检查栈顶是否与之匹配,栈为空或不匹配时整体括号无效,直接返回;括号匹配时将栈顶出栈,继续下一个括号的遍历。最后遍历结束,若栈不为空,存在多余的左括号,整体括号也是无效的。
class Solution:
def isValid(self, s: str) -> bool:
left, right = ['(', '[', '{'], [')', ']', '}']
match = {')': '(', ']': '[', '}': '{'}
stack = []
for ch in s:
if not stack and ch in right:
return False # 多了右括号
if ch in left:
stack.append(ch)
else:
if stack[-1] != match[ch]: # 栈顶不是对应的左括号
return False # 左右不匹配
else:
stack.pop()
return True if not stack else False # 多了左括号
将两个if条件合并之后:
class Solution:
def isValid(self, s: str) -> bool:
match = {')': '(', ']': '[', '}': '{'}
stack = []
for ch in s:
if ch in match:
if not stack or stack[-1] != match[ch]: # 栈为空或栈顶不是对应的左括号
return False # 左右不匹配
else:
stack.pop()
else:
stack.append(ch)
return True if not stack else False # 多了左括号
s中所有字符最多入栈出栈各一次,时间和空间复杂度都是O(n)。
LeetCode 1047. 删除字符串中的所有相邻重复项
题目链接:1047. 删除字符串中的所有相邻重复项 - 力扣(Leetcode)
这也是栈应用的一道经典题目了,利用栈暂存遍历到的字符,遇到字符与栈顶元素相同,即可出栈顶,相当于把一对相邻重复项删除了,栈为空或者字符与栈顶元素不相同则可以继续入栈。遍历结束后,栈中剩余元素即为返回结果。
class Solution:
def removeDuplicates(self, s: str) -> str:
n = len(s)
if n == 1:
return s
# 用栈
stack = []
for i in range(n):
if stack and s[i] == stack[-1]:
stack.pop() # 栈非空且当前字符与栈顶相同时, pop
else:
stack.append(s[i])
ans = ''.join(stack) # 栈最后剩下的字符就是最终的字符串
return ans
同样的,时间和空间复杂度都是O(n)。
LeetCode 150. 逆波兰表达式求值
题目链接:150. 逆波兰表达式求值 - 力扣(Leetcode)
理解逆波兰表达式的原理之后,用栈很容易实现,但实际做的时候容易被python的整除//搞崩溃,因此debug了很久:
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack = []
for ch in tokens:
if ch == '+':
a, b = stack.pop(), stack.pop()
stack.append(a + b)
elif ch == '-':
a, b = stack.pop(), stack.pop()
stack.append(b - a)
elif ch == '*':
a, b = stack.pop(), stack.pop()
stack.append(a * b)
elif ch == '/':
a, b = stack.pop(), stack.pop()
if a * b < 0:
ans = - (abs(b) // abs(a))
else:
ans = b // a
stack.append(ans)
else:
stack.append(int(ch)) # 用ch.isdigit()会漏判负数
return stack[0]