一、力扣226.翻转二叉树【easy】
题目链接:力扣226.翻转二叉树
视频链接:代码随想录
1、思路
- 利用递归,要想清楚三部曲:
- 确定递归函数的参数值和返回值:返回根节点
root
- 确定终止条件:碰到空节点停止循环
- 确定单层递归的逻辑——取决于我们是什么遍历
- 如果是前序遍历,先交换节点的左右孩子,递归处理交换后的左右子树
- 确定递归函数的参数值和返回值:返回根节点
- 时间复杂度:
O
(
n
)
O(n)
O(n),其中
n
是二叉树的节点数,每个节点恰好被访问一次
2、代码
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return None
# 先交换当前节点的左右子树
root.left , root.right = root.right , root.left
# 递归处理交换后的左右子树
self.invertTree(root.left)
self.invertTree(root.right)
return root
3、代码问题
self.invertTree(root)
:- 无限递归:每次处理当前节点时,又会重新调用自身处理同一个节点,形成死循环。
- 栈溢出:递归没有终止条件,最终引发 RecursionError。
三、力扣104.二叉树的最大深度【easy】
题目链接:力扣104.二叉树的最大深度
视频链接:灵茶山艾府
1、思路
- 递归
- 也可以迭代——队列
- 时间复杂度: O ( n ) O(n) O(n)
2、代码
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if root is None:
return 0
left_depth = self.maxDepth(root.left)
right_depth = self.maxDepth(root.right)
return max(left_depth , right_depth) + 1
三、力扣100.相同的树【easy】
题目链接:力扣100.相同的树
视频链接:灵茶山艾府
1、思路
- 递归终止条件:
- 当 p 或 q 为空时,只有两者同时为空才返回 True
- 递归比较逻辑:
- 当前节点值必须相同
- 左子树和右子树必须分别递归比较
- 时间复杂度: O ( n ) O(n) O(n)
2、代码
class Solution:
def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
# 终止条件:当p、q都为None,此时p is q return true
if p is None or q is None:
return p is q
return p.val == q.val and self.isSameTree(p.left , q.left) and self.isSameTree(p.right , q.right)
四、力扣101.对称二叉树【easy】
题目链接:力扣101.对称二叉树
视频链接:代码随想录
1、思路
- 对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,比较的是两个子树的里侧和外侧的元素是否相等。如图所示:
- 递归三部曲
- 确定递归函数的参数和返回值:左子树节点和右子树节点。
- 终止条件:左右节点都为空
- 单层递归的逻辑 :
- 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
- 比较内侧是否对称,传入左节点的右孩子,右节点的左孩子。
- 如果左右都对称就返回true ,有一侧不对称就返回false 。
- 时间复杂度: O ( n ) O(n) O(n)
2、代码
- 灵茶山艾府
class Solution:
def isMirror(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
# 终止条件:当p、q都为None,此时p is q return true
#如果pq不为None,这个if不成立,不会执行return语句
if p is None or q is None:
return p is q
return p.val == q.val and self.isMirror(p.left , q.right) and self.isMirror(p.right , q.left)
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
return self.isMirror(root.left , root.right)
- 572.另一棵树的子树【easy】-拓展
class Solution:
def isSametree(self,p: Optional[TreeNode] , q: Optional[TreeNode]) -> bool:
if p is None or q is None:
return p is q
return p.val == q.val and self.isSametree(p.left , q.left) and self.isSametree(p.right , q.right)
def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool:
if root is None:
return False
return self.isSametree(root , subRoot) or \
self.isSubtree(root.left , subRoot) or \
self.isSubtree(root.right , subRoot)
3、代码问题
五、力扣559.N叉树的最大深度【easy】
题目链接:力扣104.二叉树的最大深度
视频链接:代码随想录
1、思路
- 这是二叉树最大深度的拓展
- 时间复杂度: O ( n ) O(n) O(n)
2、代码
class Solution:
def maxDepth(self, root: 'Node') -> int:
if not root:
return 0
max_depth = 1
for child in root.children:
max_depth = max(max_depth , self.max_depth(child) +1)
六、力扣111.二叉树的最小深度【easy】
题目链接:力扣111.二叉树的最小深度
视频链接:代码随想录
1、思路
- 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。注意是叶子节点。
- 只有当左右孩子都为空的时候,才说明遍历到最低点了。如果其中一个孩子不为空则不是最低点
- 时间复杂度: O ( n ) O(n) O(n)
2、代码
class Solution:
def getDepth(self,node):
if node is None:
return 0
leftDepth = self.getDepth(node.left)
rightDepth = self.getDepth(node.right)
if node.left is None and node.right is not None:
return 1 + rightDepth
if node.right is None and node.left is not None:
return 1 + leftDepth
return 1 + min(leftDepth , rightDepth)
def minDepth(self, root: Optional[TreeNode]) -> int:
return self.getDepth(root)
- 灵神
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
ans = inf
def dfs(node: Optional[TreeNode], cnt: int) -> None:
if node is None:
return
cnt += 1
if node.left is node.right: # node 是叶子
nonlocal ans
ans = min(ans, cnt)
return
dfs(node.left, cnt)
dfs(node.right, cnt)
dfs(root, 0)
return ans if root else 0
3、代码问题
- 是我
dfs
函数的核心任务是遍历所有可能的路径并更新最小深度,而不是直接返回计算结果。它的作用是通过递归访问所有节点,并在遇到叶子节点时更新外部变量ans
。因此,它的返回值无需携带信息,只需完成遍历即可。- 叶子节点:
if node.left is None and node.right is None
- Python中的
None
是一个特殊的单例对象,所有赋值为None
的变量都指向同一个内存地址。 - 当节点的左子节点和右子节点均为
None
时,node.left
和node.right
实际上是同一个对象,node.left is node.right
会返回True
。
- Python中的
nonlocal
关键字的作用是声明一个变量属于外层嵌套函数的作用域(而非全局作用域)global
:声明变量属于全局作用域(即模块级别- 在嵌套函数中修改外层函数的变量时,必须使用nonlocal,否则Python会将其视为局部变量。