题目来源:LeetCode222:完全二叉树的节点个数
问题抽象: 高效计算完全二叉树的节点总数,需满足以下核心需求:
-
完全二叉树特性利用:
- 定义:除最后一层外,每层节点完全填充,且最后一层节点尽可能左对齐;
- 关键性质:树高
h可通过左子节点深度优先计算(时间复杂度O(h))。
-
高效计算策略:
- 递归分治:
- 计算左右子树高度
left_height和right_height; - 若
left_height == right_height:
→ 左子树为满二叉树,节点数= 2^{left_height} - 1,递归计算右子树; - 若
left_height > right_height:
→ 右子树为满二叉树(高度right_height),递归计算左子树。
- 计算左右子树高度
- 满二叉树优化:节点数直接通过高度公式
2^h - 1计算(避免遍历)。
- 递归分治:
-
时间复杂度约束:
- 最优
O(h²)(h为树高,h = log₂n):- 每层递归计算高度
O(h),递归深度O(h);
- 每层递归计算高度
- 空间复杂度
O(h)(递归栈深度)。
- 最优
-
边界处理:
- 空树返回
0; - 单节点树返回
1; - 满二叉树场景:直接返回
2^h - 1(如高度3时7个节点); - 非平衡处理:最后一层不满时递归计算子树(如左子树比右子树高
1层)。
- 空树返回
输入:完全二叉树的根节点 root(节点数 n ∈ [0, 5×10^4])
输出:整数(节点总数 n)
解题思路
利用完全二叉树的性质优化节点计数:
- 满二叉树性质:若一棵完全二叉树的左右子树高度相等,则该树为满二叉树,节点数可直接通过公式
2^h - 1计算(h为树高)。 - 递归分解:若左右子树高度不等,则说明最后一层未满,此时递归计算左右子树节点数,并加上根节点(
1)。 - 高度计算:分别计算沿左路径和右路径的高度(从当前节点出发,一直向左/右走到底的深度)。
- 时间复杂度:由于每次递归都会减少问题规模,且每次高度计算的时间复杂度为
O(log n),递归深度为O(log n),因此总时间复杂度为O((log n)^2),优于O(n)。
代码实现(Java版)🔥点击下载源码
class Solution {
public int countNodes(TreeNode root) {
if (root == null) {
return 0;
}
// 计算当前节点沿左路径的高度
int leftHeight = getHeight(root, true);
// 计算当前节点沿右路径的高度
int rightHeight = getHeight(root, false);
// 若左右高度相等,则为满二叉树,直接计算节点数
if (leftHeight == rightHeight) {
return (1 << leftHeight) - 1; // 2^h - 1
} else {
// 否则递归计算左右子树节点数,并加上根节点
return countNodes(root.left) + countNodes(root.right) + 1;
}
}
// 计算从节点node出发,沿指定方向(左或右)的高度
private int getHeight(TreeNode node, boolean isLeft) {
int height = 0;
while (node != null) {
height++;
node = isLeft ? node.left : node.right;
}
return height;
}
}
代码说明
- 递归终止条件:若当前节点为
null,返回0。 - 高度计算函数
getHeight:沿指定方向(左或右)遍历到底,统计路径长度。 - 满二叉树判断:若左右高度相等,直接通过位运算计算节点数(
(1 << h) - 1)。 - 递归分解:若左右高度不等,则递归计算左右子树节点数并加
1(根节点)。 - 效率优化:利用完全二叉树性质避免全树遍历,将时间复杂度优化至
O((log n)^2)。
提交详情(执行用时、内存消耗)

6146

被折叠的 条评论
为什么被折叠?



