226. 翻转二叉树
题目:给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
示例 1:
输入: root = [4,2,7,1,3,6,9]
输出: [4,7,2,9,6,3,1]
示例 2:
输入: root = [2,1,3]
输出: [2,3,1]
示例 3:
输入: root = []
输出: []
解题思路1:问题分解
问题分解思路,类似动态规划,明确函数定义后分解子问题,用子问题的答案推导最终答案,这里是获取左右子树深度后,取最深的再+1。
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
# 分别反转左右子树
left = self.invertTree(root.left)
right = self.invertTree(root.right)
# 交换左右子树
root.left = right
root.right = left
return root
解题思路2:回溯(DFS)
回溯的思路,traverse函数没有返回值,遍历每个节点,记录最大的深度。
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
self.traverse(root)
return root
def traverse(self, root):
if not root:
return root
# 前序位置交换左右孩子
tmp = root.left
root.left = root.right
root.right = tmp
# 递归处理左右子树
self.traverse(root.left)
self.traverse(root.right)
解题思路3:迭代(用栈模拟递归)
利用迭代版的前序遍历,孩子按照右左的顺序入栈,弹出的时候恰好为左右。在前序位置交换左右孩子节点。
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
stk = [root]
while stk:
node = stk.pop()
# 前序位置交换左右孩子
tmp = node.left
node.left = node.right
node.right = tmp
# 将右、左孩子加入stk
if node.right:
stk.append(node.right)
if node.left:
stk.append(node.left)
return root
总结
翻转二叉树的问题可以通过递归或迭代的方法解决。递归方法直观且易于实现,而迭代方法则可以避免递归带来的栈溢出风险。
101. 对称二叉树
题目:给你一个二叉树的根节点 root , 检查它是否轴对称。
示例 1:
输入: root = [1,2,2,3,4,4,3]
输出: true
示例 2:
输入: root = [1,2,2,null,3,null,3]
输出: false
解题思路
如果左右子树存在,要确保节点值相同,左子树和右子树的外侧和内侧都镜像对称。
- 时间复杂度:O()
- 空间复杂度:O()
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
return self.check(root.left, root.right)
def check(self,left, right):
# 1 两个节点都为空
if not left and not right:
return True
# 2 其中一个节点是空另一个不为空
if not left or not right:
return False
# 3 两个节点都不为空,且值相等,递归判断外侧和内侧
return left.val == right.val and self.check(left.left, right.right) and self.check(left.right, right.left)
总结
区别于反转二叉树,左右子树分别可以不对称,但是整体要对称。对称二叉树的判断需要递归地检查每个节点的左右子树是否对称。
104. 二叉树的最大深度
题目:给定一个二叉树 root ,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
示例 1:
输入: root = [3,9,20,null,null,15,7]
输出: 3
示例 2:
输入: root = [1,null,2]
输出: 2
解题思路1:问题分解
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
left_depth = self.maxDepth(root.left)
right_depth = self.maxDepth(root.right)
return max(left_depth, right_depth) + 1
解题思路2:回溯
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
self.res = 0
self.depth = 0
self.traverse(root)
return self.res
def traverse(self, root):
if not root:
return
# 前序位置,进入节点depth+1
self.depth += 1
self.res = max(self.res, self.depth)
self.traverse(root.left)
self.traverse(root.right)
# 后续位置,离开节点depth-1
self.depth -= 1
解题思路3:层序遍历
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
depth = 0
queue = [root]
while queue:
size = len(queue)
for _ in range(size):
node = queue.pop(0)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
depth += 1
return depth
总结
计算二叉树的最大深度可以通过递归或层序遍历的方法实现。
111. 二叉树的最小深度
题目:给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例 1:
输入: root = [3,9,20,null,null,15,7]
输出: 2
解题思路1:问题分解
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
left_depth = self.minDepth(root.left)
right_depth = self.minDepth(root.right)
if left_depth == 0:
return right_depth + 1
if right_depth == 0:
return left_depth + 1
return min(left_depth, right_depth) + 1
解题思路2:回溯
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
self.res = float("inf") # 注意1:取一个很大的树才能比小
self.depth = 0
self.traverse(root)
return self.res
def traverse(self, root):
if not root:
return
# 前序位置,进入节点depth+1
self.depth += 1
# 注意2:叶子节点才能更新是否是最小的深度!
if not root.left and not root.right:
self.res = min(self.res, self.depth)
self.traverse(root.left)
self.traverse(root.right)
# 后续位置,离开节点depth-1
self.depth -= 1
解题思路3:层序遍历
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
depth = 1 # 注意:如果root无左右子树,直接返回了,应该是1
queue = [root]
while queue:
size = len(queue)
for _ in range(size):
node = queue.pop(0)
if not node.left and not node.right:
return depth # 注意:层序遍历从上到下,遇到最小的直接返回啦!
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
depth += 1
return depth
总结
这道题注意和最大深度不相同,最大深度不要考虑叶子节点,因为叶子节点的深度本身最大。而最小深度必须要在叶子节点才能更新minDepth,如果左子树为空,右子树不为空,需要记为右子树的深度+1,而非当前节点深度。