[路飞]算法:222. 完全二叉树的节点个数

172 阅读2分钟

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

正题

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

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

示例1

image.png

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

示例 2:

输入: root = []
输出: 0

示例 3:

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

解析:

假设我们不考虑该二叉树是完全二叉树,我们如何求的所有节点个数呢?这个还是比较简单的,我们可以先从这个角度出发去解决问题。

一. 简单递归求解二叉树节点个数

var countNodes = function(root) {
    if (root === null) {
        return 0
    }
    return 1 + countNodes(root.left) + countNodes(root.right)
};

以上代码原理很简单,通过递归,每一次递归都分别累加左树和右树的节点个数,当节点为 null的时候就返回 0,如果不是 null,就返回1,表示个数+1,最后再将左右节点的总个数相加,再加上根节点的1即可。

image.png

这个算法很显然是可以通过的,而且适用于所有情况的二叉树。

二.完全二叉树求解

在以上求解过程中并没有用到完全二叉树这一个重要的信息,而是使用了普通的求二叉树节点个数的求解方法。所以我就在考虑题目为什么要界定这个条件呢?一定是完全二叉树有更好的求解方案或是可以当树而完全二叉树的时候以上算法可以得到优化。

回顾一下完全二叉树的定义:

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

总结来说就是除了最后一层节点,其余n层都是 2 * n 个节点。

所以完全二叉树情况下,我们可以先求解得出二叉树深度,然后再利用公式进行计算,这里借用官方算法:

const exists = (root, level, k) => {
    let bits = 1 << (level - 1);
    let node = root;
    while (node !== null && bits > 0) {
        if (!(bits & k)) {
            node = node.left;
        } else {
            node = node.right;
        }
        bits >>= 1;
    }
    return node !== null;
}

var countNodes = function(root) {
    if (root === null) {
        return 0;
    }
    let level = 0;
    let node = root;
    while (node.left !== null) {
        level++;
        node = node.left;
    }
    let low = 1 << level, high = (1 << (level + 1)) - 1;
    while (low < high) {
        const mid = Math.floor((high - low + 1) / 2) + low;
        if (exists(root, level, mid)) {
            low = mid;
        } else {
            high = mid - 1;
        }
    }
    return low;
};