算法学习 day15 二叉树3

108 阅读4分钟

110. 平衡二叉树

文章讲解

视频讲解

题目:给定一个二叉树,判断它是否是 平衡二叉树

示例 1:

输入: root = [3,9,20,null,null,15,7]
输出: true

示例 2:

输入: root = [1,2,2,3,3,null,null,4,4]
输出: false

解题思路

如果节点为空,返回 0。 递归计算左右子树的高度,存储在 left 和 right 变量中。 如果左右子树的高度差大于 1,或者左右子树有一个不平衡,则返回 -1。 否则,返回左右子树高度的最大值加 1。

  • 时间复杂度:O(n)
  • 空间复杂度:O(h)
class Solution:
    def isBalanced(self, root: Optional[TreeNode]) -> bool:
        return self.getHight(root) != -1

    def getHight(self, root):
        if not root:
            return 0
        left_hight = self.getHight(root.left)
        right_hight = self.getHight(root.right)

        # 如果左右子树其中一棵不平衡,或者左右子树的高度差>1,非平衡
        if left_hight == -1 or right_hight == -1 or abs(left_hight- right_hight) > 1:
            return -1
        
        return max(left_hight, right_hight) + 1

总结

这道题目考察了二叉树的遍历和递归思想。通过递归计算每个节点的左右子树高度,并判断是否满足平衡二叉树的条件,从而得出最终的结果。这种自底向上的递归方式,可以很好地解决这类需要从子问题推导出父问题的题目。

257. 二叉树的所有路径

文章讲解

视频讲解

题目:给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

叶子节点 是指没有子节点的节点。

 

示例 1:

输入: root = [1,2,3,null,5]
输出: ["1->2->5","1->3"]

解题思路

回溯,使用track数组记录当前路径的节点值,进入节点时加入值,离开节点时候删除值。遇到叶子节点时候将当前路径加入到result。

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n^2)
class Solution:
    def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
        self.result = []
        track = []
        self.traverse(root, track)
        return self.result

    def traverse(self, root, track = []):
        if not root:
            return 

        # 前序位置加入节点
        track.append(str(root.val))
        if not root.left and not root.right:
            self.result.append("->".join(track))
        self.traverse(root.left, track)        
        self.traverse(root.right, track)        

        # 后续位置删除节点
        track.pop()

404. 左叶子之和

文章讲解

视频讲解

题目:给定二叉树的根节点 root ,返回所有左叶子之和。 示例 1:

输入: root = [3,9,20,null,null,15,7] 
输出: 24 
解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

示例 2:

输入: root = [1]
输出: 0

解题思路

  • 时间复杂度:O()
  • 空间复杂度:O()
class Solution:
    def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        
        self.results = [0] # 记录左叶子值
        self.traverse(root, is_left=False)
        return sum(self.results)


    def traverse(self, root, is_left = False):
        if not root:
            return 
        
        # 前序位置进入节点做处理
        if not root.left and not root.right and is_left:
            self.results.append(root.val)

        self.traverse(root.left, is_left=True)
        self.traverse(root.right, is_left=False)

222. 完全二叉树的节点个数

文章讲解

视频讲解

题目:给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

示例 1:

输入: root = [1,2,3,4,5,6]
输出: 6

解题思路1:层次遍历

完全二叉树指除了底层其他每一层节点数量达到最大值,底层左边是满的,高度为h数量为1~2^h -1

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        queue = [root]
        result = 0
        while queue:
            size = len(queue)
            for _ in range(size):
                node = queue.pop(0)
                result += 1
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)

        return result

解题思路2:递归

  • 时间复杂度:O(n)
  • 空间复杂度:O(logn),算上了递归系统栈占用的空间
class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        return 1 + self.countNodes(root.left) + self.countNodes(root.right)

解题思路3:递归时考虑满二叉树

  • 时间复杂度:O(lognxlogn)
  • 空间复杂度:O(logn)
# 讨论满二叉树的情况
class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0

        pl, pr = root, root # pl往左遍历 pr往右遍历
        nl, nr = 0, 0 # nl,nr分别记录左右子树的高度
        while pl:
            pl = pl.left
            nl += 1
        while pr:
            pr = pr.right
            nr += 1          
        if nl == nr:
            return 2**nl - 1

        return 1 + self.countNodes(root.left) + self.countNodes(root.right)