研习代码 day14 | 二叉树的最大、最小深度 && 完全二叉树的节点数

一、二叉树的最大深度

        1.1 题目

        给定一个二叉树 root ,返回其最大深度。

        二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

示例 1:

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

示例 2:

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

提示:

  • 树中节点的数量在 [0, 10^4] 区间内。
  • -100 <= Node.val <= 100

        1.2 题目链接

        104.二叉树的最大深度

        1.3 解题思路和过程想法

        (1)解题思路:

        1)递归高度:高度--从下往上高度递增----左右根----递归

        # 递归的传入参数与返回值:“根”节点指针,树的高度。
        # 递归出口:遇见空指针
        # 主体:计算左子树的高度 l ,计算右子树的高度 r ,树的高度 = max(l,r) + 1

        2)层序遍历:在层序遍历的过程中记录树的层数

        (2)过程想法:

        题目比较经典,思考过程比较自然。但是如果利用前序遍历的话,可能就有点复杂了,想等到学到回溯板块的时候再回来看看。

        1.4 代码

        1.4.1 递归高度
class Solution:
    # 递归的传入参数与返回值:“根”节点指针,树的高度
    def height(self,root) -> int:
        # 递归出口:遇见空指针
        if not root:
            return 0
        # 主体:计算左子树的高度 l ,计算右子树的高度 r ,树的高度 = max(l,r) + 1
        l = self.height(root.left)
        r = self.height(root.right)
        root_height = max(l,r) + 1

        return root_height

    def maxDepth(self, root: Optional[TreeNode]) -> int:
        # 高度--从下往上高度递增----左右根----递归
        return self.height(root)
        1.4.2 层序遍历 
from queue import Queue

class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        # 在层序遍历的过程中记录树的层数。

        # 用来存储结果
        res = 0
        # 用来层序遍历的队列
        myQueue = Queue()

        # 层序遍历
        if root:
            myQueue.put(root)
        while not myQueue.empty():
            size = myQueue.qsize()
            for i in range(size):
                cur = myQueue.get()
                if cur.left:
                    myQueue.put(cur.left)
                if cur.right:
                    myQueue.put(cur.right)
            
            # 更新树的层数
            res += 1

        return res

二、二叉树的最小深度

        2.1 题目

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明:叶子节点是指没有子节点的节点。

示例 1:

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

示例 2:

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

提示:

  • 树中节点数的范围在 [0, 10^5] 内
  • -1000 <= Node.val <= 1000

        2.2 题目链接

        111.二叉树的最小深度

        2.3 解题思路和过程想法

        (1)解题思路

        1)后序遍历递归:区别于二叉树的最大深度

        # 递归的传入参数:“根”节点指针,树的深度。
        # 递归出口:遇见空指针
        # 主体:计算左子树的高度 l ,计算右子树的高度 r ,根据数的情况求最小高度

        2)层序遍历:在层序遍历的过程中记录树的层数,最早出现的叶节点的层数就是二叉树的最小深度。

        (2)过程想法

        题目比较经典,思考过程比较自然,但是在后序遍历的时候卡了一下,因为最小深度还是和最大深度有很大差别的。如果利用前序遍历的话,可能就有点复杂了,想等到学到回溯板块的时候再回来看看。

        2.4 代码

        2.4.1 递归高度
class Solution:
    def minn(self,root) -> int:
        if not root:
            return 0
        # 左
        l = self.minn(root.left)
        # 右
        r = self.minn(root.right)
        # 根
        if root.left and not root.right:
            res = l + 1
        elif root.right and not root.left:
            res = r + 1
        else:
            res = min(l,r) + 1

        return res        

    def minDepth(self, root: Optional[TreeNode]) -> int:
        # 总体思路:借助后序遍历递归,求左子树最小“深度”,求右子树最小“深度”,求根的最小“深度”
        # 求根的最小深度不能直接写 res = min(l,r) + 1,因为若有一方为空,则会取到它的深度
        # 但它实际不符合“叶子节点”的要求,故而需要分情况讨论
        return self.minn(root)
        2.4.2 层序遍历 
from queue import Queue

class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        # 在层序遍历的过程中记录树的层数,最早出现的叶节点的层数就是二叉树的最小深度

        # 用来存储结果
        res = 0
        # 用来层序遍历的队列
        myQueue = Queue()

        # 层序遍历
        if root:
            myQueue.put(root)
        while not myQueue.empty():
            size = myQueue.qsize()
            for i in range(size):
                cur = myQueue.get()
                # 记录叶子结点的层数
                if not cur.left and not cur.right:
                    return res + 1
                if cur.left:
                    myQueue.put(cur.left)
                if cur.right:
                    myQueue.put(cur.right)
            
            # 更新树的层数
            res += 1

        return res

三、完全二叉树的节点个数

        3.1 题目

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

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

示例 1:

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

示例 2:

输入:root = []
输出:0

示例 3:

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

提示:

  • 树中节点的数目范围是[0, 5 * 10^4]
  • 0 <= Node.val <= 5 * 10^4
  • 题目数据保证输入的树是 完全二叉树

进阶:遍历树来统计节点是一种时间复杂度为 O(n) 的简单解决方案。你可以设计一个更快的算法吗?

        3.2 题目链接

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

        3.3 解题思路和过程想法

        (1)解题思路

        1)普通树-------后序遍历递归:

        # 递归的传入参数与返回值:“根”节点指针,树的结点数
        # 递归出口:遇见空指针
        # 主体:计算左子树的结点数 l ,计算右子树的结点数 r ,树的高度 = l + r + 1

        2)普通树--------层序遍历:

        在层序遍历的过程中记录树的层数。

        3)完全二叉树:

        # 充分利用完全二叉树的性质以计算节点数量----满二叉树或最后一层叶子节点没有满
        # n 层满二叉树的节点数为 2^n-1(完全二叉树是满二叉树的判断方式:向左递归的深度等于向右递归的深度)
        # 充分利用此题中满二叉树的判断特性,不必遍历全部节点即可计算数的节点数
        # 最后结合后序遍历递归计算整棵树的结点树

        (2)过程想法

        题目比较经典,普通树的节点计算方式是简单的,但本题特意强调了是完全二叉树,结合前者特性,才能使判断满二叉树变得简单(之前有思考要用完全二叉树的性质,但没想到这个思路)。

        3.4 代码

        3.4.1 后序遍历递归
class Solution:
    def count(self,root) -> int:
        if not root:
            return 0
        # 左
        l = self.count(root.left)
        # 右
        r = self.count(root.right)
        # 根
        h = l + r + 1

        return h

    def countNodes(self, root: Optional[TreeNode]) -> int:   
        # 利用后序遍历递归:左右根
        # 先计算左子树节点数,再计算右子树节点数,后计算总结点数       
        return self.count(root)
        3.4.2 层序遍历
from queue import Queue

class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        # 通过层序遍历,统计节点个数

        # 用于层序遍历的队列
        myQueue = Queue()
        # 用于统计节点的变量
        res = 0

        # 层序遍历
        if root:
            myQueue.put(root)
        while not myQueue.empty():
            cur = myQueue.get()
            # 统计节点数量
            res += 1
            if cur.left:
                myQueue.put(cur.left)
            if cur.right:
                myQueue.put(cur.right)
            
        return res
        3.4.3 利用完全二叉树性质
class Solution:
    
    def countNodes(self, root: Optional[TreeNode]) -> int:   
        # 充分利用完全二叉树的性质以计算节点数量----满二叉树或最后一层叶子节点没有满
        # n 层满二叉树的节点数为 2^n-1(完全二叉树是满二叉树的判断方式:向左递归的深度等于向右递归的深度)
        # 充分利用此题中满二叉树的判断特性,不必遍历全部节点即可计算数的节点数
        # 最后结合后序遍历递归计算整棵树的结点树

        # 递归出口 
        if not root:
            return 0

        # 记录左右子树的深度
        leftDepth = 0
        rightDepth = 0

        # 初始化左右指针
        left_p = root.left
        right_p = root.right

        # 向左递归,计算左侧深度
        while left_p:
            leftDepth += 1
            left_p = left_p.left

        # 向右递归,计算右侧深度
        while right_p:
            rightDepth += 1
            right_p = right_p.right

        # 如果左右侧深度相同,则是满二叉树,返回其节点个数
        if leftDepth == rightDepth:
            return (2 << leftDepth) -1
        
        # 后序遍历--左右根
        # 左
        leftNodes = self.countNodes(root.left)
        # 右
        rightNodes = self.countNodes(root.right)
        # 根
        res = leftNodes + rightNodes + 1

        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值