算法学习 day14 二叉树2

63 阅读5分钟

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,而非当前节点深度。