// 定义二叉树节点
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val) { this.val = val; }
}
public 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;
}
}
104.二叉树的最大深度
当我们在 maxDepth
方法中使用递归时,我们实际上是在将问题不断地分解为更小的子问题,并通过递归调用来解决这些子问题。
在这个问题中,我们需要计算二叉树的最大深度,即从根节点到叶子节点的最长路径上的节点数。我们可以将这个问题分解为计算左子树和右子树的最大深度的两个子问题,并将其结果合并,从而得到整个二叉树的最大深度。
我们从根节点开始,对于每个节点,都有两个可能的子节点:左子节点和右子节点。我们可以通过递归地调用 maxDepth
方法来计算左子树和右子树的最大深度。
递归的终止条件是遇到空节点,即节点为 null
。空节点表示树的末端,没有子节点,所以其深度为 0。
递归调用的过程中,每次都会将当前节点的左子节点和右子节点作为参数传递给递归调用。递归会一直深入到树的末端,即叶子节点处停止。
然后,递归会从叶子节点开始逐层返回,计算每个节点的最大深度。对于每个节点,我们通过取其左子树和右子树的最大深度中较大的那个值,并加 1,得到当前节点的最大深度。
最终,递归调用会返回到根节点处,得到整个二叉树的最大深度。这样,我们通过递归调用解决了计算二叉树最大深度的问题。
● 111.二叉树的最小深度
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public class Solution {
public int minDepth(TreeNode root) {
if (root == null) {
// 如果根节点为空,说明到达了树的末端,返回深度为0
return 0;
} else if (root.left == null && root.right == null) {
// 如果根节点没有左子节点和右子节点,说明是叶子节点,返回深度为1
return 1;
} else if (root.left == null) {
// 如果只有右子节点,递归计算右子树的最小深度并加1
return minDepth(root.right) + 1;
} else if (root.right == null) {
// 如果只有左子节点,递归计算左子树的最小深度并加1
return minDepth(root.left) + 1;
} else {
// 如果同时有左子节点和右子节点,递归计算左右子树的最小深度,并取较小值加1
return Math.min(minDepth(root.left), minDepth(root.right)) + 1;
}
}
}
- 首先,定义了一个名为
TreeNode
的类,表示二叉树的节点。每个节点包含一个整数值(val
),以及左子节点(left
)和右子节点(right
)。 - 接着,在
Solution
类中,定义了一个名为minDepth
的方法,用于计算二叉树的最小深度。该方法接收一个TreeNode
类型的参数root
,表示二叉树的根节点。 - 在
minDepth
方法中,首先进行了空节点的检查。如果root
是空节点(即null
),说明当前节点为空,返回深度为 0。 - 然后,判断根节点的左子树和右子树的情况:
- 如果根节点没有左子树,那么只需计算右子树的最小深度,并在结果上加 1,表示当前节点到叶子节点的深度。即
minDepth(root.right) + 1
。 - 如果根节点没有右子树,同样地,只需计算左子树的最小深度,并在结果上加 1,表示当前节点到叶子节点的深度。即
minDepth(root.left) + 1
。
- 如果根节点没有左子树,那么只需计算右子树的最小深度,并在结果上加 1,表示当前节点到叶子节点的深度。即
- 最后,如果根节点既有左子树又有右子树,那么需要比较左右子树深度的较小值,并在结果上加 1,表示当前节点到叶子节点的深度。即
Math.min(minDepth(root.left), minDepth(root.right)) + 1
。 - 递归地调用
minDepth
方法,通过遍历整个二叉树,找到最小深度。
222.完全二叉树的节点个数
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
public int countNodes(TreeNode root) {
if (root == null) {
return 0;
}
int leftHeight = leftHeight(root);
int rightHeight = rightHeight(root);
if (leftHeight == rightHeight) {
// 如果左子树的高度等于右子树的高度,说明左子树是一棵满二叉树
// 左子树的节点个数可以通过公式 2^leftHeight - 1 计算,再加上根节点,再递归计算右子树的节点个数
return (1 << leftHeight) - 1 + countNodes(root.right);
} else {
// 如果左子树的高度不等于右子树的高度,说明右子树是一棵满二叉树
// 右子树的节点个数可以通过公式 2^rightHeight - 1 计算,再加上根节点,再递归计算左子树的节点个数
return (1 << rightHeight) - 1 + countNodes(root.left);
}
}
// 计算左子树的高度
private int leftHeight(TreeNode root) {
int height = 0;
while (root != null) {
height++;
root = root.left;
}
return height;
}
// 计算右子树的高度
private int rightHeight(TreeNode root) {
int height = 0;
while (root != null) {
height++;
root = root.right;
}
return height;
}
public static void main(String[] args) {
// 构造完全二叉树: [1,2,3,4,5,6]
TreeNode root = new TreeNode(1);
TreeNode node1 = new TreeNode(2);
TreeNode node2 = new TreeNode(3);
TreeNode node3 = new TreeNode(4);
TreeNode node4 = new TreeNode(5);
TreeNode node5 = new TreeNode(6);
root.left = node1;
root.right = node2;
node1.left = node3;
node1.right = node4;
node2.left = node5;
Solution solution = new Solution();
int nodeCount = solution.countNodes(root);
System.out.println("完全二叉树的节点个数为: " + nodeCount); // 输出:完全二叉树的节点个数为: 6
}
}
-
首先判断根节点是否为空,若为空则直接返回0,表示节点个数为0。
-
然后分别计算左子树和右子树的深度,使用两个循环来分别计算左子树深度和右子树深度。循环中不断通过访问左孩子节点(left)和右孩子节点(right)来向下遍历,同时使用一个变量(leftDepth和rightDepth)来记录深度,直到遍历到最底层节点为止。
-
接下来,比较左子树深度和右子树深度(通过比较leftDepth和rightDepth),如果相等,说明左子树是满二叉树,此时可以直接使用位运算计算节点个数,即
(2 << leftDepth) - 1
。这是因为在满二叉树中,节点个数可以通过 2 的深度次方减 1 来计算得到。 -
如果左子树深度和右子树深度不相等,说明右子树不是满二叉树,需要分别计算左子树和右子树的节点个数,并加上根节点,得到最终的节点个数。使用递归调用,分别计算左子树和右子树的节点个数,然后加上根节点,返回结果。
这种解法对于完全二叉树的情况效率较高,因为通过位运算和循环可以快速计算满二叉树的节点个数,避免了重复计算。但需要注意的是,这种解法仅适用于完全二叉树,不适用于普通的二叉树。在其他类型的二叉树中,左子树和右子树的高度可能会不同,无法使用位运算来计算节点个数。