题也太多了……
DFS和BFS的区别
1、深度优先搜索(DFS):
- 遍历方式: 从一个子树深入到另一个子树,从底层往上遍历,直到遍历完整个树。
- 实现方式: 通常使用递归(如前序遍历、中序遍历、后序遍历)或者使用栈。
- 特点: DFS会沿着树的一个分支尽可能深入,然后再回溯到上一层继续遍历其他分支。
2、广度优先搜索(BFS):
- 遍历方式: 一层一层地遍历,从根节点开始,先遍历当前层的所有节点,再遍历下一层的节点。
- 实现方式: 通常使用队列。
- 特点: BFS会首先访问离根节点最近的节点,然后逐层向下遍历。
因为TreeNode的存储方式是从上到下从左到右存储,为空的存为Null。一般是链表形式存储,一个节点存三个数据[val, left指针, right指针] 。
从底层回溯刚好用栈(先进后出),层序则用队列(先进先出)
层序遍历 10 (BFS)
from collections import deque
# 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]]:
if not root:#树为空直接return
return []
deque = collections.deque([root])#根节点
res = []
while deque:#deque不为空的时候(还有节点),一直循环
level = []#用于存储本层的节点的值
for i in range(len(deque)):#当层队列的长度,循环一次后,队列长度会变成下一层队列的长度
cur = deque.popleft()
level.append(cur.val)
## 判断左右节点不为空就放入deque,别忘了!
if cur.left:#左节点不为空,就把左节点加入队列
deque.append(cur.left)
if cur.right:
deque.append(cur.right)
res.append(level)
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 levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
levels = []
self.helper(root,0,levels)#修改levels对象,在类内修改,因此helper函数不需要return
return levels[::-1]#倒序输出
# helper 是类内函数,所以需要加一个self
def helper(self,node,level,levels):#节点,层序号,数据存储容器(输入参数)
if not node:#终止条件
return
#每一层递归要做的事
if len(levels) == level:#在当前层次,加一个空列表用于append
levels.append([])
levels[level].append(node.val)#存储当前节点的值
self.helper(node.left, level+1, levels)#本节点的左节点(下一层)
self.helper(node.right, level+1, levels)#本节点的右节点(下一层)
依然是递归三要素:输入输出、终止条件、每一层要干的事
十个题都是这个套路,不再一一给出代码(一题递归一题for循环练习)
637.二叉树的层平均值
这个题是用for写感觉会好理解很多,递归写,要对遍历回来的数据进行遍历。自己写的时候苦恼的是无法获取层序号。借助了GPT,想到了字典的性质:用字典的key存序号,val是每层的值。
字典的新函数:dict.keys()--->获取所有key
注意key的索引是dict[key]
# 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]:
if not root:
return []
levels = dict()#如果想用递归法写,如果用list存储无法查阅层数
self.helper(root,0,levels)
levels_avg = []
for level in sorted(levels.keys()):#按keys的大小排序
print(level)
levels_avg.append(sum(levels[level])/len(levels[level]))
return levels_avg
def helper(self,node,level,levels):
if not node:
return
if level not in levels:
levels[level] = [] # 初始化每层的列表
levels[level].append(node.val)#level是key
self.helper(node.left,level+1,levels)
self.helper(node.right,level+1,levels)
429.N叉树的层序遍历
同样的遍历模板,但是子节点不是用left、right来储存的,而是node.children这样储存的
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
from collections import deque
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
if not root:
return []
res = []
deque = collections.deque([root])
while deque:
level = []
for i in range(len(deque)):
cur = deque.popleft()
level.append(cur.val)
# deque.append(cur.left) #一个节点有多个孩子因子不是用左右来储存
# deque.append(cur.right)
for child in cur.children:
deque.append(child)
res.append(level)
return res
如果要对每层中的数据做筛选还是for循环比较方便,递归简直是在为难自己……
226.翻转二叉树
不能用中序遍历做,中序遍历的顺序是左中右,在遍历左子树的时候就会对左子树操作一次,把他换到右子树,那么在做右子树的时候,会把这些节点再交换一遍,就又换回去了。
因此只能用前后序遍历做,或者层序遍历
哎呀,层序遍历比深度优先遍历好理解多了……比较符合我的思考逻辑……
可恶,怎么还优先掌握递归!!!!!
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
from collections import deque
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
deque = collections.deque([root])
while deque:
cur = deque.popleft()
cur.left,cur.right = cur.right,cur.left#交换顺序
if cur.left:
deque.append(cur.left)
if cur.right:
deque.append(cur.right)
return root
2、前序遍历的递归写法
# 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 invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return
self.dfs(root)
return root
#注意这个递归函数缩进和其他函数在同一个位置,而不是invertTree的子函数
def dfs(self,node):#输入参数
if not node:#终止条件
return
#每次递归要做的事
node.left,node.right = node.right,node.left#交换节点
self.dfs(node.left)#到下一个节点
self.dfs(node.right)
前中后序思路差别不大,不再做复现
101.对称二叉树 2
这个题的思路完全6,左半边用前序遍历(中左右),右半边用后序遍历(左右中,非严格后序)
不可以按照这个顺序把左右子树全读出来之后在进行比较:只有一个子树时无法判断是哪个子树
outside:比较左半边的左子树和右半边的右子树
inside:比较左半边的右子树和右半边的左子树
# 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 isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
res = self.compara(root.left,root.right)
return res
def compara(self,leftnode,rightnode):#输入输出
## 要对比的结果(每层递归要做的事)+终止条件
##有空节点的三种情况
if leftnode == None and rightnode != None: return False#
elif leftnode != None and rightnode == None: return False
elif leftnode == None and rightnode == None: return True
# 无空节点,比较数值,注意是比较数值!!!
elif leftnode.val != rightnode.val: return False
#两个节点的值相等,跳到下一层比较
outside = self.compara(leftnode.left,rightnode.right)#外侧那条路
inside = self.compara(leftnode.right,rightnode.left)#内侧的一半
return outside and inside#
补不过来了,二刷再来看其他方法