持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情
题目
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h 个节点。
示例 1
输入:root = [1,2,3,4,5,6]
输出:6
示例 2
输入:root = []
输出:0
示例 3
输入:root = [1]
输出:1
提示
- 树中节点的数目范围是[0, 5 * 10^4]
- 0 <= Node.val <= 5 * 10^4
- 题目数据保证输入的树是 完全二叉树
题解
思路
本题可以把输入当成普通二叉树,直接遍历所有节点统计个数也可以,但是为了结合题目中给定的完全二叉树的条件可采用如下思路:
首先明确几个概念:
- 完全二叉树:它是一棵空树或者它的叶子节点只出在最后两层,若最后一层不满则叶子节点只在最左侧。
- 满二叉树:对于一个二叉树,如果每一个层的结点数都达到最大值,那么称之为满二叉树。
- 完全二叉树的节点数(没有公式) = 左子树节点数 + 右子树节点数
- 满二叉树的节点个数(有公式) = 2^树的高度 - 1
明确概念,问题就变得简单了
设 root 的左右子树高度分别为 l_height 和 r_height ,有两种情况:
- 若
l_height == r_height说明此时root树的叶节点已经填充到了右子树(若填充满了,则右子树和整棵树都是满二叉树),所以其左子树必是满二叉树,所以树的节点数 = + 根 + 右子树节点数(因为右子树不一定满,需要继续递归),即 + countNodes(右子树),使用位运算加快幂运算效率后可得(1 << l_height) + countNodes(right)。 - 若
l_height != r_height说明此时root树的叶节点还未填充到右子树,而且左子树还不知道有没有填满最后一层。但是需要注意,此时root树的倒数第二层是满的,所以可以发现,右子树反倒成为满二叉树了(尽管是比左子树高度少1),所以树的节点数 = + root + 左子树节点数,同理最终为(1 << r_height) + countNodes(left)。
代码
class Solution {
private:
int getHeight(TreeNode* root) {
if (! root) return 0;
int height = 1;
while (root->left)
{
root = root->left;
height++;
}
return height;
}
public:
int countNodes(TreeNode* root) {
if (! root) return 0;
int cnt = 0;
auto left = root->left, right = root->right;
int l_height = getHeight(left);
int r_height = getHeight(right);
if (l_height == r_height)
return (1 << l_height) + countNodes(right);
else
return (1 << r_height) + countNodes(left);
}
};
结语
业精于勤,荒于嬉;行成于思,毁于随。