代码随想录算法训练营第十二天(二叉树篇)|Leetcode226翻转二叉树,Leetcode101对称二叉树,Leetcode104二叉树的最大深度,Leetcode111二叉树的最小深度
Leetcode 226 翻转二叉树
题目链接: 翻转二叉树
给定一棵二叉树根节点,将二叉树整体进行翻转后,仍然返回其根节点
如对于二叉树
4
/ \
2 7
/ \ / \
1 3 6 9
翻转后得到:
4
/ \
7 2
/ \ / \
9 6 3 1
思路: 观察题目我们知道,我们只需要将二叉树中每一个节点的左右孩子节点互换位置,最终即可实现整颗二叉树的翻转。为此我们可以通过递归遍历二叉树。
在写出递归代码之前,我们需要通过递归三部曲,明确我们的目标和每一步的操作。
- 递归函数的参数与返回值:
当前递归函数的参数应当为当前正在遍历的节点,返回值为空。由于最终返回二叉树根节点即可,因此递归函数不需要返回值。 - 递归终止条件:
当前节点为空节点时,终止当前递归 - 每层递归进行的操作
将当前的左右节点进行交换
具体代码实现:
class Solution:
def traverse(self, cur: Optional[TreeNode]) -> None:
if cur is None:
return
cur.left, cur.right = cur.right, cur.left
self.traverse(cur.left)
self.traverse(cur.right)
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
self.traverse(root)
return root
Leetcode 101 对称二叉树
题目链接: 对称二叉树
给定一棵二叉树,判断其是否为对称二叉树(判断其是否沿着左右两侧对称)
如以下二叉树属于对称二叉树:
4
/ \
3 3
/ \ / \
1 2 2 1
思路: 同样利用递归三部曲进行分析:
- 递归函数参数与返回值
递归函数参数为当前需要进行比较的两个镜像节点,譬如左侧二叉树的左节点和右侧二叉树的右节点,返回值为一个布尔值,表示当前二叉树是否对称 - 递归终止条件
分不同情况讨论: 若当前待比较的两个节点均不存在,则返回真;若仅存在其中任意一个节点,或者两个节点均存在,但是值不相同,则返回假 - 每层递归完成的操作
将这两个节点对应子节点的结果进行 AND 操作,并向上层传递
具体代码实现
class Solution:
def check(self, left: Optional[TreeNode], right: Optional[TreeNode]) -> bool:
if left is None and right is None: # 待比较的左右节点均不存在
return True
if left is None or right is None: # 若仅存在其中任意一个节点
return False
if left.val != right.val: # 值不相同
return False
return self.check(left.left, right.right) and self.check(left.right, right.left) # 将孩子节点比较的结果向上传递
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if root is None:
return True
return self.check(root.left, root.right)
Leetcode 104 二叉树的最大深度
题目链接: 二叉树的最大深度
给定一棵二叉树,返回该二叉树的最大深度,如对于以下二叉树:
4
/ \
3 20
/ \
15 7
其最大深度为3。
思路: 从二叉树根节点出发,到二叉树叶子节点结束,求的是二叉树的深度;对应的,从二叉树的叶子节点出发,到二叉树根节点结束,求的是二叉树的高度。若我们通过递归法求解此题,从二叉树叶子节点开始,一路向根节点返回的实际上是二叉树的高度而非深度。
不过在此题中,二叉树的最大深度和最大高度的值实际上是相同的。
利用递归三部曲进行分析:
- 递归函数参数与返回值
递归函数的函数参数为当前正在遍历的节点,返回值为二叉树的最大深度 - 递归函数的终止条件
当前遍历的节点为空时终止递归 - 每层递归时进行的操作
将当前节点的两个孩子的深度取最大值,向上层返回即可
具体代码实现
class Solution:
def getDepth(self, cur: Optional[TreeNode]) -> int:
if cur is None:
return 0
return 1 + max(self.getDepth(cur.left), self.getDepth(cur.right))
def maxDepth(self, root: Optional[TreeNode]) -> int:
return self.getDepth(root)
Leetcode 111 二叉树的最小深度
题目链接: 二叉树的最小深度
给定一个二叉树,求该二叉树的最小深度。需要特别注意,二叉树的最小深度应该从距离该二叉树根节点距离最近的叶子节点处开始计算
如给定以下二叉树,求该二叉树的最小深度:
4
\
20
\
7
该二叉树的最小深度为3,因为根节点到距离其最近的叶子节点 7
之间的高度差为3
思路: 与二叉树的最大深度不同,我们不能在当前节点为空时返回0,因为这样会计入一边孩子节点为空的情况,而这不符合我们的预期。我们的预期是在遇到叶子节点时再向上返回当前的高度。如何判断当前节点为叶子节点呢?只需要检查当前节点的两个孩子节点是否为空即可。
通过递归三部曲进行分析:
- 递归函数参数与返回值
递归函数的参数为当前遍历的节点,返回值为二叉树的最小深度 - 递归函数的终止条件
当前节点的两个孩子节点均为空节点时,说明当前节点为叶子节点,终止递归操作 - 每层递归时进行的操作
需要分情况进行讨论:若当前节点仅存在一个孩子,则将对应孩子递归得到的高度上传即可。若两个孩子节点均存在,则将两个孩子节点的高度取最小值,向上返回即可
具体代码实现
class Solution:
def getDepth(self, cur: Optional[TreeNode]) -> int:
if cur.left is None and cur.right is None:
return 1
if cur.left and cur.right is None:
return 1 + self.getDepth(cur.left)
if cur.right and cur.left is None:
return 1 + self.getDepth(cur.right)
return 1 + min(self.getDepth(cur.left), self.getDepth(cur.right))
def minDepth(self, root: Optional[TreeNode]) -> int:
if root is None:
return 0
return self.getDepth(root)