题一:20. 有效的括号
链接
视频总结
关键点
- 总共只有三种情况:(] ; ( ; )
编程思路
卡尔:
- 遇到左括号时把对应的右括号加入栈里面(遇左放右比遇左放左easy点)
- 遇到右括号时判断是否和栈头的一样,一样则栈pop,不一样则False
- 遍历到右括号,发现已经为空了,说明右多了,false
- 当处理完之后,如果为空就说明ture,否则false,多了左括号
- 考虑剪枝操作,匹配时一定是偶数个,若为奇数则是false
- 在循环到空栈时,先把空栈的条件放在前面,否则对空栈pop的话会异常
力扣实战
思路一:
# 方法一,仅使用栈,更省空间
class Solution:
def isValid(self, s: str) -> bool:
stack = []
for item in s:
if item == '(':
stack.append(')')
elif item == '[':
stack.append(']')
elif item == '{':
stack.append('}')
elif not stack or stack[-1] != item:
return False
else:
stack.pop()
return True if not stack else False
# 反思1:
思路二:
# 方法二,使用字典
class Solution:
def isValid(self, s: str) -> bool:
stack = []
mapping = {
'(': ')',
'[': ']',
'{': '}'
}
for item in s:
if item in mapping.keys():
stack.append(mapping[item])
elif not stack or stack[-1] != item:
return False
else:
stack.pop()
return True if not stack else False
文档总结
1. 由于栈结构的特殊性,非常适合做对称匹配类的题目。
题二: 1047. 删除字符串中的所有相邻重复项
链接
视频总结
关键点
编程思路
Me:
- 思路,使用栈方法,逐个加入栈,如果和栈顶相同,则pop,这样一次遍历即可
卡尔:
- 栈适合解决括号匹配类问题,此处字母匹配也是同样的道理
- 通过栈的思想来理解题目,但不一定最后使用完整的栈来实现,比如此处可以用字符串来模拟栈的效果
力扣实战
思路一:
class Solution:
def removeDuplicates(self, s: str) -> str:
# 使用数组来模拟栈,当result不为空,且数组最后一个字符和当前字符相等时,才满足pop条件,否则加入栈
result = []
for i in s:
if result and result[-1]==i:
result.pop()
else:
result.append(i)
return ''.join(result)
# 反思1:
思路二:
# 双指针法,帅的都不谈,独立分析出流程,内啡肽直接拉满
class Solution:
def removeDuplicates(self, s: str) -> str:
# 使用双指针来模拟栈;慢的功能是用来存储的,慢指向零表示栈空,此时快值直接给慢(进栈),快慢均加一
#快加一表示下一个即将进栈的元素的索引,慢加一表示栈里已经有了一个位置了,且加一之后指向新的位置,如果有新的元素进栈,
#则可以放在慢的加一之后的位置
result = list(s)
slow = fast = 0
length = len(result)
while fast<length:
result[slow] = result[fast] # 快元素即将进栈,和栈里的头元素比,如相同则正是进栈,正式进栈只需把慢加一,以为慢前面的元素表示已经在栈里面的元素。
if slow>0 and result[slow] == result[slow-1]: # 大于零表示栈不为空,后面就是题目判别调节
slow -=1 #相等时慢减一,表示即将进栈的元素
else:
slow +=1 # 此时栈空或者不等,表示当前的快元素成功进栈,成功的标志即慢往后移动一位,表示慢前的元素在栈内,而+1后的位置表示预备进栈的元素
fast +=1
return ''.join(result[:slow])
文档总结
1. 递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
相信大家应该遇到过一种错误就是栈溢出,系统输出的异常是Segmentation fault(当然不是所有的Segmentation fault 都是栈溢出导致的) ,如果你使用了递归,就要想一想是不是无限递归了,那么系统调用栈就会溢出。
而且在企业项目开发中,尽量不要使用递归!在项目比较大的时候,由于参数多,全局变量等等,使用递归很容易判断不充分return的条件,非常容易无限递归(或者递归层级过深),造成栈溢出错误(这种问题还不好排查!)
题三: 150. 逆波兰表达式求值
链接
视频总结
关键点
-
波兰表达式是一种后缀表达式,是一种利于计算机运算的形式,由二叉树的例子可见,采用后序可以在不加括号时也没有歧义
而若想让计算机顺序处理字符串就得到想要的结果,就是使用栈的方法。(来处理后缀表达式) -
具体流程:遇见数字就加入到栈里面,遇见操作符时就从栈里取出两个数字进行运算,然后再把数字加入到栈里
-
拓展栈用法边界:相邻匹配比如左右括号匹配,比如相邻字符相同,或者相邻字符符合特殊条件就做相应的消除
编程思路
Me:
学习波兰表达式
卡尔:
力扣实战
思路一:
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
#思路:用栈的思想,用数组实现,遇到数字就进栈,遇到运算符就 取出两个元素运算然后再放进栈里
stack = list()
for i in tokens:
if i =='+' or i =='-' or i =='*' or i =='/':
nums1 = stack[-1] # 需要把字符串类型变为整形,否则字符串类型无法数学运算
stack.pop()
nums2 = stack[-1]
stack.pop()
if i == '+':
stack.append(nums1+nums2)
elif i == '-':
stack.append(nums2-nums1) # 注意减法是谁减谁
elif i == '*':
stack.append(nums1*nums2)
else:
stack.append(int(nums2/nums1)) # 注意除法是谁除以谁,在整数除法中,除法 / 总是返回一个浮点数,如果只想得到整数的结果,丢弃可能的分数部分,可以使用运算符 // :
else:
stack.append(int(i))
return stack[-1]
# 反思1:本题代码需要尤其注意,字符串类型的数字不能数学运算,需要转成数字型;python除法默认获得的是浮点数,若有需要得转成整形
文档总结
1. 文档里的文字部分值得反复观看!!非常好