20. 有效的括号
Leetcode 20 原题链接
本题要匹配上的括号有三种:( ), { }, [ ]。由于栈结构的特殊性,非常适合做对称匹配类的题目。当我们接受到左括号的时候,我们往栈里加入对应的右括号,当匹配到对应的右括号,就可以直接从栈里弹出这个右括号。因此,栈顶元素会一直变化,匹配完的括号会被排出以方便直接记录的括号可以继续匹配。
不匹配的情况分为三种:
- 存在多余左括号,最终栈里的右括号没有匹配完,即不为空。
- 存在多余右括号,当遍历到这个多余右括号时,栈顶元素不为此括号,或者此时栈里元素为空,也就没办法抵消。
- 不存在多余情况,但是遍历到的右括号,无法和应该抵消的左括号匹配,也就是此时栈顶元素不等于遍历到的右括号。
class Solution:
def isValid(self, s: str) -> bool:
stack=[]
for element in s:
if element=="(":
stack.append(")")
elif element=="[":
stack.append("]")
elif element=="{":
stack.append("}")
# 记录对应左括号的右括号
elif stack==[] or stack[-1]!=element:
# 解决情况2和3
return False
else:
stack.pop()
return True if not stack else False
# 解决情况1
字典法思路和栈的思路相似,只是用字典来检索。
# 字典法
class Solution:
def isValid(self, s: str) -> bool:
stack=[]
para={
"(":")",
"{":"}",
"[":"]"
}
for i in s:
if i in para.keys():
stack.append(para[i])
elif stack==[] or stack[-1]!=i:
return False
else:
stack.pop()
return True if not stack else False
1047. 删除字符串中的所有相邻重复项
Leetcode 1047 原题链接
我们依然可以将其看作匹配问题,而匹配问题就可以尝试用栈来模拟解决。当遍历到和栈顶元素不同的元素时,将其输入到栈里;而如果和栈顶元素匹配,说明相邻元素重复,直接以从栈里弹出该栈顶元素的方式作为抵消。
class Solution:
def removeDuplicates(self, s: str) -> str:
stack=[]
for i in s:
if stack==[] or stack[-1]!=i:
# 记入不和相邻元素重复的元素
stack.append(i)
else:
stack.pop()
return "".join(stack)
双指针法可以参考下。本质上slow是操作指针,可以看作slow在记录经历的不重复元素,最后输出[0:slow]的元素。fast是终止指针,当它遍历完所有元素停止,且若存在重复相邻元素,让slow往后退一格,fast继续前进,来看作中间相邻元素被抹除,而fast依旧会指向下一个要检索判定的元素。
class Solution:
def removeDuplicates(self, s: str) -> str:
res = list(s)
slow = fast = 0
length = len(res)
while fast < length:
# 如果一样直接换,不一样会把后面的填在slow的位置
res[slow] = res[fast]
# print(res,res[slow],res[fast])
# 如果发现和前一个一样,就退一格指针
if slow > 0 and res[slow] == res[slow - 1]:
slow -= 1
else:
slow += 1
fast += 1
# print(f"slow:",slow)
# print(f"fast",fast)
return ''.join(res[0: slow])
150. 逆波兰表达式求值
Leetcode 150 原题链接
逆波兰表达式优点:适合用栈操作运算,遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
def calculate(num1:int,num2:int,i:str)->int:
if i=="+": return num1+num2
elif i=="-": return num1-num2
elif i=="*": return num1*num2
elif i=="/": return int(num1/num2)
stack=[]
for i in tokens:
if i not in {"+","-","*","/"}:
stack.append(int(i))
else:
num2=stack.pop() # 先弹出的数字在减法和除法是被减和被除的对象
num1=stack.pop()
stack.append(calculate(num1,num2,i))
return stack.pop()
或者用字典,对应的value为运算函数。
from operator import add, sub, mul
class Solution:
op_map = {'+': add, '-': sub, '*': mul, '/': lambda x, y: int(x / y)}
def evalRPN(self, tokens: List[str]) -> int:
stack = []
for token in tokens:
if token not in {'+', '-', '*', '/'}:
stack.append(int(token))
else:
op2 = stack.pop()
op1 = stack.pop()
stack.append(self.op_map[token](op1, op2)) # 第一个出来的在运算符后面
return stack.pop()