题一:
链接
视频总结
关键点
- 使用队列实现,一套模板解决十个
力扣实战
①102. 二叉树的层序遍历
思路一:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
from collections import deque
que = deque() # # 创建队列 便于层序操作
result =[] # 记录最终结果,二维数组,每个元素是一维数组
if root != None: # root 不是空时才加入队列 # if not root:写法也可
que.append(root)
while len(que)!=0: # 队列不为空,用长度来写,若用!= None,会超时,在一轮外层循环后队列为空,说明all儿子讨论完了 # while que:
size = len(que) # 记录当前层的节点数,否则不知道需要弹出队列里的多少个数至当前层的vector
vector = [] # 记录每一层的节点的值
while size: # 此时前面的循环执行了,所以size一定大于零,size等于零时说明当前层的数遍历完了
node = que.popleft() # 弹出当前节点
size -= 1
vector.append(node.val) # 数值取出
if node.left != None: # 因为用数组模拟队列,所以先加入右儿子,这样可以先pop左儿子
que.append(node.left)
if node.right != None:
que.append(node.right)
result.append(vector)
return result
# 反思1:
思路二:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
# 递归法
res = []
def func(cur,depth): # depth 用于记录深度,也用于记录res里每一层的索引
if not cur:
return[]
if len(res)==depth:
res.append([])
res[depth].append(cur.val)
if cur.left:
func(cur.left,depth+1)
if cur.right:
func(cur.right,depth+1)
return res
func(root,0)
return res
②107. 二叉树的层序遍历 II
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
# 思路:对102题翻转一下
res = []
def func(cur,depth):
if not cur:
return []
if len(res)==depth: # 这一行if必须加上,否则在结尾处会多两个[],因为当左儿子递归时,res已经有depth+1个了,此时还是这么多层,在递归右儿子时不需要在多加一个空格
res.append([])
res[depth].append(cur.val)
if cur.left:
func(cur.left,depth+1)
if cur.right:
func(cur.right,depth+1)
return res
func(root,0)
res.reverse()
return res
③199.二叉树的右视图
法一
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
# 思路,层序递归遍历,稍作改动即可
res=[]
def func(cur,depth):
if not cur:
return []
if len(res) == depth:
res.append(0) # res为一维数组,于是无需传入数组,而是传入一个数值占位置,否则后面无法索引到
res[depth] = cur.val #这里既是深度,也是res里每一层的那个数的索引,每次把每层vector里的最后一个元素传入res里,递归就是不是append,而是赋值
if cur.left:
func(cur.left,depth+1)
if cur.right:
func(cur.right,depth+1)
return res
func(root,0)
return res
法二
#每一层的点都放进去,然后取这一层的最后一个赋值
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
# deque来自collections模块,不在力扣平台时,需要手动写入
# 'from collections import deque' 导入
# deque相比list的好处是,list的pop(0)是O(n)复杂度,deque的popleft()是O(1)复杂度
quene = deque([root])
out_list = []
while quene:
# 每次都取最后一个node就可以了
node = quene[-1]
out_list.append(node.val)
# 执行这个遍历的目的是获取下一层所有的node
for _ in range(len(quene)):
node = quene.popleft()
if node.left:
quene.append(node.left)
if node.right:
quene.append(node.right)
return out_list
④637.二叉树的层平均值
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
# """二叉树层平均值迭代解法"""
results = []
if not root:
return results
from collections import deque
que = deque([root])
while que:
size = len(que)
sum_ = 0 #直接也不储存了,直接sum一下
for _ in range(size): # 只是改变了次数的遍历
cur = que.popleft()
sum_ += cur.val
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
results.append(sum_ / size) # 此时体现除了for写法的好处,没有改变size的大小
return results
文档总结
1. deque里的append和extend?二叉树用append,n茶树用extend附加节点
2. 116,117填充每个节点的下一个右侧节点指针,这一题有点难度,可能做不粗来。
题二:226.翻转二叉树
链接
视频总结
关键点
编程思路
卡尔:递归三部曲
- 确定返回值和参数。分别是TreeNode和root
- 终止条件:遇到空时终止
- 确定递归顺序 :前后都可,中有点麻烦,若选择前序,也即是前中后,其中前后是递归,中是操作的语句
力扣实战
思路一:
# 递归法有前中后三种顺序,前后只是调整语句的顺序,而中需要改掉后递归的儿子
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
root.left, root.right = root.right, root.left #中
self.invertTree(root.left) #左
self.invertTree(root.right) #右
return root
# 反思1:
思路二:
# 迭代法指深度优先、广度优先。
# 深度前序
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return root
st = []
st.append(root)
while st:
node = st.pop()
node.left, node.right = node.right, node.left #中
if node.right:
st.append(node.right) #右
if node.left:
st.append(node.left) #左
return root
# 广度
import collections
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
queue = collections.deque() #使用deque()
if root:
queue.append(root)
while queue:
size = len(queue)
for i in range(size):
node = queue.popleft()
node.left, node.right = node.right, node.left #节点处理
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return root
文档总结
1. 针对二叉树的问题,解题之前一定要想清楚究竟是前中后序遍历,还是层序遍历。
二叉树解题的大忌就是自己稀里糊涂的过了(因为这道题相对简单),但是也不知道自己是怎么遍历的。
这也是造成了二叉树的题目“一看就会,一写就废”的原因。
题三:101. 对称二叉树
链接
视频总结
关键点
- 了解其遍历顺序:需要收集所有的孩子的信息返还给上一个节点时,则只能够使用后续遍历
- 考察同时处理两个二叉树的过程
- 原题意等价于判断对称二叉树也就是判断左右孩子是否可以翻转
- 单层递归的逻辑,单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况。
编程思路
Me:
卡尔:
力扣实战
思路一:
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
# 在初步学习的时候不要过于追求所谓简洁的代码,代码越简洁,就会漏掉很多的细节,这对初学者来说是很坏的情况
if not root:
return True
return self.compare(root.left, root.right)
def compare(self, left, right):
#首先排除空节点的情况
if left == None and right != None: return False
elif left != None and right == None: return False
elif left == None and right == None: return True
#排除了空节点,再排除数值不相同的情况
elif left.val != right.val: return False
#此时就是:左右节点都不为空,且数值相同的情况
#此时才做递归,做下一层的判断
outside = self.compare(left.left, right.right) #左子树:左、 右子树:右
inside = self.compare(left.right, right.left) #左子树:右、 右子树:左
isSame = outside and inside #左子树:中、 右子树:中 (逻辑处理)
return isSame
# 反思1:
文档总结
1. 在初步学习的时候不要过于追求所谓简洁的代码,代码越简洁,就会漏掉很多的细节,这对初学者来说是很坏的情况