第六章 二叉树part03 104.二叉树的最大深度 559.n叉树的最大深度 111.二叉树的最小深度 222.完全二叉树的节点个数

第十六天| 第六章 二叉树part03 104.二叉树的最大深度 559.n叉树的最大深度 111.二叉树的最小深度 222.完全二叉树的节点个数

一、104.二叉树的最大深度

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)

  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始)

  • 题解给出的是:“本题可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。“

  • 但是我认为使用后序遍历也可以求深度,具体地:

  • (1)使用后序遍历求深度

    • 从根节点出发,记录从根节点出发左右子树的最大深度**(左右),然后将最大的深度返回给根节点(中)** ((左右)—> 中:左右收集信息返回给中
    • 代码:
    class Solution {
        public int maxDepth(TreeNode root) {
            int depth = 0;
            return levelDepth(root, depth);
        }   
    
        public int levelDepth(TreeNode root, int depth) {
            if (root == null) {
                return depth;
            }
            depth++;
            int leftDepth = levelDepth(root.left, depth);
            int rightDepth = levelDepth(root.right, depth);
            return Math.max(leftDepth, rightDepth);
        }
    }
    
  • (2)使用后序遍历求高度==(从叶子节点从0开始求高度)==

  • 代码:

class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftDepth = maxDepth(root.left);
        int rightDepth = maxDepth(root.right);
        return Math.max(leftDepth, rightDepth) + 1;
    }   
}

以上两段代码的区别在于,求深度的时候遇到null,返回的是当前距离根节点深度depth;求高度的时候遇到null,从0开始记录当前的高度。

  • 深度:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5sWrDkRv-1692881189749)(后序遍历求深度.png)]

  • 高度:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c0EEU4rP-1692881189750)(后序遍历求高度.png)]

  • (3)迭代:
class Solution {
    public int maxDepth(TreeNode root) {
        Deque<TreeNode> queue = new LinkedList<>();
        int depth = 0;
        if (root != null) {
            queue.offer(root);
        }
        while (!queue.isEmpty()) {
            int size = queue.size();
            while (size-- > 0) {
                TreeNode tempNode = queue.poll();
                if (tempNode.left != null) {
                    queue.offer(tempNode.left);
                }
                if (tempNode.right != null) {
                    queue.offer(tempNode.right);
                }
            }
            depth++;
        }
        return depth;
    }   
}

二、559.n叉树的最大深度

  • (1)后序遍历求高度:
class Solution {
    public int maxDepth(Node root) {
        int max = 0;
        if (root == null) {
            return 0;
        }
        if (root.children != null) {
            for (Node child : root.children) {
            	int childDepth = maxDepth(child);
            	max = max < childDepth ? childDepth : max;
            }
        }
        return max + 1;
    }
}
  • (2)层序遍历,迭代:
class Solution {
    public int maxDepth(Node root) {
        Deque<Node> queue = new LinkedList<>();
        int depth = 0;
        if (root != null) {
            queue.offer(root);
        }
        while (!queue.isEmpty()) {
            int size = queue.size();
            while (size-- > 0) {
                Node tempNode = queue.poll();
                for (Node child : tempNode.children) {
                    if (child != null) {
                        queue.offer(child);
                    }
                }
            }
            depth++;
        }
        return depth;
    }
}

三、111.二叉树的最小深度

  • (1)递归(后序遍历)
class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftDepth = minDepth(root.left);
        int rightDepth = minDepth(root.right);
        if (root.left == null && root.right != null) {
            return rightDepth + 1;
        }
        if (root.right == null && root.left != null) {
            return leftDepth + 1;
        }
        return Math.min(leftDepth, rightDepth) + 1;
    }
}
  • 注意:和求最大深度的整体思路是一样的,但是这里要注意,这里的最小深度求的是**根节点到叶子节点的最小距离**(一定要注意是叶子节点),

  • 什么是叶子节点,左右孩子都为空的节点才是叶子节点!

  • 因此,要特殊处理以下情况:

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v9kVVLVz-1692881189750)(二叉树最小深度.png)]

    • 这里如果直接进行下面三行的代码,就会把root节点的到它的左节点认为是最小深度

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KKhz3uC5-1692881189750)(最小深度代码.png)]

  • 所以我们要判断,如果左空右不空,最小深度就是右子树的深度 + 1(返回给它们的根节点);如果右空左不空,最小深度就是左子树的深度 + 1(返回给它们的根节点);

  • (2)迭代:

class Solution {
    public int minDepth(TreeNode root) {
        Deque<TreeNode> queue = new LinkedList<>();
        int depth = 0;
        if (root != null) {
            queue.offer(root);
        }
        while (!queue.isEmpty()) {
            int size = queue.size();
            while (size-- > 0) {
                TreeNode tempNode = queue.poll();
                if (tempNode.left != null) {
                    queue.offer(tempNode.left);
                }
                if (tempNode.right != null) {
                    queue.offer(tempNode.right);
                }
                if (tempNode.left == null && tempNode.right == null) {
                    depth++;
                    return depth;
                }
            }
            depth++;
        }
        return depth;
    }
}

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

  • 题目链接:https://leetcode.cn/problems/count-complete-tree-nodes/

  • 题目介绍:

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

    • 满二叉树

      满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ni8GSe7f-1692881189751)(满二叉树.png)]

      这棵二叉树为满二叉树,也可以说深度为k,有2^k-1个节点的二叉树。

    • 完全二叉树

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

      我来举一个典型的例子如题:

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K59toJVE-1692881189751)(完全二叉树.png)]

      相信不少同学最后一个二叉树是不是完全二叉树都中招了。

      之前我们刚刚讲过优先级队列其实是一个堆,堆就是一棵完全二叉树,同时保证父子节点的顺序关系。

  • 思路:

    • (1)不利用完全二叉树特性(适用于一般的二叉树):
    class Solution {
        public int countNodes(TreeNode root) {
            if (root == null) {
                return 0;
            }
            int leftNums = countNodes(root.left);
            int rightNums = countNodes(root.right);
            return leftNums + rightNums + 1;
        }
    }
    
    • (2)利用完全二叉树的特性(具体特性如下:)
      • 首先,如果有一个满二叉树,节点个数 = 2 ^ (树的深度) - 1;
      • 我们可以从这个点出发,找到完全二叉树中的满二叉树
        • 在完全二叉树中,如何快速的判断子树是不是一个满二叉树呢?
          • 只要保证从该节点遍历左子树得到的深度 == 从该节点遍历右子树得到的深度。比如下面这种情况:
          • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S7SONK4E-1692881189752)(image-20230824182630842.png)]
          • 可能会有一个疑问,如下图打叉的位置万一没有元素呢?
          • 事实上,这种情况是不可能出现在完全二叉树中的,如果蓝色可以遍历到最后的右子节点,说明打红叉的两个位置一定有元素,因为在完全二叉树的定义中,明确规定了:“最下面一层的节点都集中在该层最左边的若干位置”。
          • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YkVKLZZT-1692881189752)(image-20230824182736322.png)]
class Solution {
    public int countNodes(TreeNode root) {
        // 1. 判断递归结束的条件
        //  1.1 遇到null
        //  1.2 如果左右子树的深度相同,返回该满二叉树的节点个数
        
        // 1.1 遇到null
        if (root == null) {
            return 0;
        }
        //  1.2 如果左右子树的深度相同,返回该满二叉树的节点个数
        TreeNode leftCur = root.left;
        TreeNode rightCur = root.right;
        int leftDepth = 1;
        int rightDepth = 1;
        while (leftCur != null) {
            leftCur = leftCur.left;
            leftDepth++;
        }
        while (rightCur != null) {
            rightCur = rightCur.right;
            rightDepth++;
        }
        if (leftDepth == rightDepth) {
            return (int)Math.pow(2, rightDepth) - 1;
        }

        // 2. 每一层的逻辑
        //  2.1 计算左子树的节点个数
        // countNodes(root.left);
        //  2.2 计算右子树的节点个数
        // countNodes(root.right);
        //  2.3 返回左 + 右 + 1
        return countNodes(root.left) + countNodes(root.right) + 1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值