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

难度中等659收藏分享切换为英文接收动态反馈

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

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

示例 1:

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

示例 2:

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

示例 3:

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

提示:

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

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

题解:

迭代法:层序遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public int countNodes(TreeNode root) {
int res = 0;
if (root == null) {
return res;
}
//层序遍历,记录节点的个数

Queue<TreeNode> que = new ArrayDeque<>();

que.offer(root);

while (!que.isEmpty()) {

int len = que.size();
while (len > 0) {
TreeNode node = que.poll();
res++;
if (node.left != null) {
que.offer(node.left);
}

if (node.right != null) {
que.offer(node.right);
}
len--;
}

}
return res;
}
  • 时间复杂度:O(N)
  • 空间复杂度:O(N)

递归:

1
2
3
4
5
6
7
8
public int countNodes(TreeNode root) {
//树为空直接返回0
if (root == null){
return 0;
}
//树不为空,返回左子树节点数量加右子树节点数量加当前节点
return countNodes(root.left) + countNodes(root.right) + 1;
}
  • 时间复杂度:O(N)
  • 空间复杂度:O(logN),递归系统栈占用的空间

完全二叉树性质

完全二叉树只有两种情况:

  1. 满二叉树
  2. 最后一层叶子结点没有满

对于情况1,满二叉树的节点数 N = 2 ^ depth - 1,根节点深度为1

对于情况2,分别递归左孩子和右孩子,递归到某一个深度一定会有左孩子或者右孩子有满二叉树,然后按照情况1来计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public int countNodes(TreeNode root) {
if (root == null) {
return 0;
}

int leftDepth = getDepth(root.left);
int rightDepth = getDepth(root.right);

//左子树深度等于右子树深度,证明左子树是完全二叉树
if (leftDepth == rightDepth) {
//将左子树的节点数算出来,然后通过递归去算出右子树的节点数
return (1 << leftDepth) - 1 + countNodes(root.right) + 1;

}else {
//左子树深度不等于右子树深度,则证明右子树为完全二叉树
return (1 << rightDepth) - 1 + countNodes(root.left) + 1;
}
//左子树深度不等于右子树深度,证明不是完全二叉树
// 递归其左右孩子,加上根节点



}

int getDepth(TreeNode root) {
int depth = 0;
//计算树的深度
while (root != null) {
root = root.left;
depth++;
}
return depth;
}
  • 时间复杂度:O(logN * logN)
  • 空间复杂度:O(logN)