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

136 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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树的叶节点已经填充到了右子树(若填充满了,则右子树和整棵树都是满二叉树),所以其左子树必是满二叉树,所以树的节点数 = 2l_height12^{l\_height} - 1 + 根 + 右子树节点数(因为右子树不一定满,需要继续递归),即 2l_height22^{l\_height}2 + countNodes(右子树),使用位运算加快幂运算效率后可得(1 << l_height) + countNodes(right)。
  • l_height != r_height 说明此时root树的叶节点还未填充到右子树,而且左子树还不知道有没有填满最后一层。但是需要注意,此时root树的倒数第二层是满的,所以可以发现,右子树反倒成为满二叉树了(尽管是比左子树高度少1),所以树的节点数 = 2r_height12^{r\_height} - 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);
    }
};

结语

业精于勤,荒于嬉;行成于思,毁于随。