文章目录
day16学习内容
day16主要内容
- 二叉树的最大深度
- 二叉树的最小深度
- 完全二叉树的节点个数
声明
本文思路和文字,引用自《代码随想录》
一、二叉树的最大深度
1.1、思路
- 求最大深度,就是求最大高度,那么这题就转化成为了求树的最大高度
- 最大高度怎么求
- 从根节点出发,计算左右子树每一个节点的高度,最后求和就是树的最大高度
- 假设左子树高度为L,右子树高度为R
- 最后就是max(L,R)+1,不停的递归求解即可。
1.2、正确写法
后序遍历
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;
}
}
代码没看明白的,直接去看题解,题解里面有流程图。或者看我1.3的代码
1.3、测试用例
public class MaxDepth {
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {
}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
public static int maxDepth(TreeNode root) {
// 调用辅助方法,初始深度为1,根节点作为起始点
return maxDepthHelper(root, 1, "根节点");
}
private static int maxDepthHelper(TreeNode root, int depth, String nodePosition) {
if (root == null) {
System.out.println("递归到第 " + depth + " 层,当前节点为null(" + nodePosition + "),返回深度 0");
return 0;
}
System.out.println("递归到第 " + depth + " 层,当前节点值为 " + root.val + "(" + nodePosition + ")");
int leftDepth = maxDepthHelper(root.left, depth + 1, "左节点");
int rightDepth = maxDepthHelper(root.right, depth + 1, "右节点");
int result = Math.max(leftDepth, rightDepth) + 1;
System.out.println("从 " + nodePosition + "(值为 " + root.val + ")第 " + depth + " 层的最大深度是 " + result);
return result;
}
public static void main(String[] args) {
TreeNode node7= new TreeNode(7,null,null);
TreeNode node6= new TreeNode(15,null,null);
TreeNode node3= new TreeNode(20,node6,node7);
TreeNode node2= new TreeNode(9,null,null);
TreeNode node1= new TreeNode(3,node2,node3);
System.out.println(maxDepth(node1));
}
}
输出就省略了,自己贴到编辑器里面运行一下。
二、二叉树的最小深度
2.1、思路
- 使用递归实现翻转
2.2、正确写法
class Solution {
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
// 左
int minLeft = minDepth(root.left);
// 右
int minRight = minDepth(root.right);
// 中
if (root.left == null && root.right != null) {
return 1 + minRight;
}
if (root.left != null && root.right == null) {
return 1 + minLeft;
}
return Math.min(minLeft, minRight) + 1;
}
2.2.1 如何理解上面的代码
- 基本情况: 如果根节点 root 为空,说明树为空,其最小深度自然为 0。
- 递归左子树: 计算左子树的最小深度,保存在变量 minLeft 中。
- 递归右子树: 计算右子树的最小深度,保存在变量 minRight 中
- 处理特殊情况:
- 如果左子节点为空而右子节点不为空,这意味着树的最小深度是通过右子节点计算得到的。这是因为按照最小深度的定义,我们需要找到的是从根节点到最近叶子节点的最短路径,而一个空的左子树不会计入路径。因此,返回 1 + minRight,1 表示当前节点本身。
- 如果右子节点为空而左子节点不为空,最小深度通过左子节点计算得到,返回 1 + minLeft。
- 一般情况:
- 如果既有左子节点也有右子节点,这意味着我们需要在左右子树的最小深度中取较小的一个,然后加 1 来包括根节点本身在内的总深度。
三、完全二叉树的节点个数
3.1、思路
- 普通二叉树的求法
- 利用完全二叉树性质的求法
3.2、普通二叉树的求法
class Solution {
public int countNodes(TreeNode root) {
if (root == null) {
return 0;
}
int leftCount = countNodes(root.left);
int rightCount = countNodes(root.right);
return leftCount + rightCount + 1;
}
}
代码和思路都比较简单,就不多介绍了
3.3、利用完全二叉树性质的求法
3.3.1 完全二叉树有什么性质?
- 完全二叉树是一种特殊的二叉树,除了最底层外,每一层都被完全填满,并且所有节点都尽可能地集中在左侧。
- 满二叉树的节点总数可以直接通过树的深度计算出来,公式为 2depth−1。这里的 depth 是从 1 开始计数的树的层数。
3.3.2 思路
- 基本判断:首先检查树是否为空。如果树为空,即没有节点,直接返回节点数为0。
- 计算深度:分别计算从根节点出发到最左边叶子节点和最右边叶子节点的路径长度,即左深度和右深度。这是通过沿着左子树一直往左走,以及沿着右子树一直往右走来实现的。
- 判断是否为满二叉树:
- 如果左深度等于右深度,说明当前考察的树(或子树)是一个满二叉树。对于满二叉树,可以直接使用公式 2depth−1计算节点总数,其中depth是树的深度。
- 递归分治:
- 如果左深度不等于右深度,说明当前考察的树是一个非满的完全二叉树。此时不能直接用满二叉树的节点计算公式,需要递归地计算左子树和右子树的节点数,然后加上根节点本身(+1)来得到总节点数。
- 递归终止条件:递归地应用以上步骤,直至到达叶子节点。对于叶子节点,左右深度均为0,可以直接应用满二叉树的公式,或者视为特殊的递归终止条件。
3.3.3 代码
class Solution {
public int countNodes(TreeNode root) {
if (root == null) return 0;
TreeNode left = root.left;
TreeNode right = root.right;
int leftDepth = 0;
int rightDepth = 0;
// 计算左子树深度
while (left != null) {
left = left.left;
leftDepth++;
}
// 计算右子树深度
while (right != null) {
right = right.right;
rightDepth++;
}
//如果是满二叉树,直接用公式计算
if (leftDepth == rightDepth) {
return (2 << leftDepth) - 1;
}
//不是满二叉树,继续递归
return countNodes(root.left) + countNodes(root.right) + 1;
}
}
3.3.4、测试用例
class Solution {
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {
}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
public static int countNodes(TreeNode root) {
if (root == null) {
System.out.println("当前节点为null,高度为0,节点总数为0");
return 0;
}
int leftDepth = getDepth(root.left);
int rightDepth = getDepth(root.right);
// 如果是满二叉树,直接用公式计算
if (leftDepth == rightDepth) {
int totalNodes = (2 << leftDepth) - 1;
System.out.println("节点 " + root.val + " 的子树是满二叉树,高度为: " + (leftDepth + 1) + ",节点总数为: " + totalNodes);
return totalNodes;
}
// 不是满二叉树,继续递归
int leftCount = countNodes(root.left);
int rightCount = countNodes(root.right);
int totalNodes = leftCount + rightCount + 1; // 加上根节点本身
System.out.println("节点 " + root.val + " 的子树不是满二叉树,左子树高度为: " + leftDepth + ",右子树高度为: " + rightDepth + ",节点总数为: " + totalNodes);
return totalNodes;
}
// 辅助方法用于计算深度
private static int getDepth(TreeNode node) {
int depth = 0;
while (node != null) {
depth++;
node = node.left; // 沿左子树一直向下遍历以求得深度
}
return depth;
}
public static void main(String[] args) {
TreeNode node5 = new TreeNode(5, null, null);
TreeNode node4 = new TreeNode(4, null, null);
TreeNode node3 = new TreeNode(3, null, null);
TreeNode node2 = new TreeNode(2, node4, node5);
TreeNode node1 = new TreeNode(1, node2, node3);
System.out.println(countNodes(node1));
}
}
假设树为以下格式、
1
/ \
2 3
/ \
4 5
总结
1.感想
- 第二题不难,但是我想了半天。
2.思维导图
本文思路引用自代码随想录,感谢代码随想录作者。