leetcode
leetcode 201 ~ 250
完全二叉树的节点个数

完全二叉树的节点个数

难度:

标签:

题目描述

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

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

 

示例 1:

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

示例 2:

输入:root = []
输出:0

示例 3:

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

 

提示:

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

 

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

代码结果

运行时间: 80 ms, 内存: 21.7 MB


// 思路:我们可以使用Java Stream来实现遍历树的节点并统计个数。我们可以通过递归收集所有节点到一个列表中,然后使用stream的count方法来统计个数。
 
import java.util.*;
import java.util.stream.*;
 
public class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        List<TreeNode> nodes = new ArrayList<>();
        collectNodes(root, nodes);
        return (int) nodes.stream().count();
    }
 
    private void collectNodes(TreeNode node, List<TreeNode> nodes) {
        if (node != null) {
            nodes.add(node);
            collectNodes(node.left, nodes);
            collectNodes(node.right, nodes);
        }
    }
}
 
// TreeNode是树节点的类定义,假设如下:
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

解释

方法:

该题解采用了递归的思路,利用完全二叉树的性质来优化计算节点个数的过程。首先通过 get_height 函数递归计算完全二叉树的高度。如果高度小于等于1,直接返回高度作为节点个数。否则,通过判断右子树的高度是否等于总高度减2,如果是,说明左子树是一个满二叉树,可以直接计算左子树的节点数,再加上右子树递归计算的节点数;如果右子树高度不等于总高度减2,说明右子树是一个满二叉树,可以直接计算右子树的节点数,再加上左子树递归计算的节点数。通过这样的方式,可以避免遍历整棵树,从而降低时间复杂度。

时间复杂度:

O((log n)^2)

空间复杂度:

O(log n)

代码细节讲解

🦆
在递归函数`get_height`中,为什么只计算左子树的高度,而不是同时考虑左右子树的高度?
在完全二叉树中,如果一个节点的左子树的高度等于右子树的高度,则该节点及其所有子树构成一个满二叉树,所以可以通过只计算左子树高度快速确定树的高度。这是因为在完全二叉树中,节点是从左到右依次填充的,左子树总是比右子树先填满或同时填满。因此,左子树的高度可以作为判断整棵树高度的关键指标。
🦆
递归计算高度时的基准情况是什么?即在`get_height`函数中,当什么条件满足时返回0?
在`get_height`函数中,基准情况是当节点不存在(即节点为`None`)时返回0。这表示树是空的,因此没有高度。这是递归计算树高度的终止条件,保证了每次递归能够在遇到叶节点的子节点时停止。
🦆
在判断右子树的高度是否等于总高度减2时,这种条件判断对于完全二叉树的结构有何重要意义?
这种条件判断对于快速确定树的结构非常关键。如果右子树的高度等于总高度减2,则意味着左子树是一个满二叉树且与最底层除最右侧外完全填满,而右子树可能还未完全填满。这样可以利用满二叉树的节点数性质直接计算左子树的节点数,而不需要逐节点遍历,从而提高效率。如果不符合这个条件,则右子树是一个满二叉树,而左子树未完全填满,同样可以快速计算右子树的节点数并递归计算左子树。
🦆
题解中使用的`(1 << (height - 2))`和`(1 << (height - 1))`分别是如何计算满二叉树的节点数的?
在二叉树中,满二叉树的节点数可以通过计算`2^k - 1`得到,其中`k`是树的高度。在位操作中,`1 << n`表示`2^n`。因此,`(1 << (height - 2))`计算的是高度为`height-1`的满二叉树的节点数,而`(1 << (height - 1))`计算的是高度为`height`的满二叉树的节点数。这些计算利用位移操作提高计算效率,并直接得到对应高度的满二叉树的节点总数。

相关问题

最接近的二叉搜索树值

最接近的二叉搜索树值