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

背景知识:

  完全二叉树:除了最后一层,所有层的节点数达到最大,与此同时,最后一层的所有节点都在最左侧。(堆使用完全二叉树)

  满二叉树:所有层的节点数达到最大。一棵层数为 h 的满二叉树,其节点数为2^h - 1个。

思路1:层序遍历 或 递归 遍历整棵树。 但没用到 完全二叉树 的性质。。不可取

思路2:左神P178 ,        时间复杂度为O(h^2), h为完全二叉树的层数

  知识点1:层数为h的满二叉树的节点数为2^h - 1个

  知识点2:完全二叉树的高度可以直接通过不断地访问左子树就可以获取

具体步骤为:

  (1)如果不是空树,求完全二叉树的高度。求法是找到树的最左节点看能到哪一层,层数记为h

  (2)递归函数 bs(node, l ,h)的返回值表示以node为头的完全二叉树的节点数是多少。l表示node所在的层数,h表示整棵树的层数是始终不变的。初始时,node为头节点head, l 为 1

  找到node右子树的最左节点,如果能到达最后一层,见(2.1),如果不能,见(2.2)

    (2.1)第一种情况:说明node的整棵左子树是满二叉树,并且层数为h-l 。 node的整棵左子树再加上node本身,节点数为2^(h-l)-1+1. 此时再递归求出node右子树的节点数即可。 bs(node.right, l + 1, h) 。 因此,整体为2^(h-l)+bs(node.right, l + 1, h)

    (2.2)第二种情况:说明node的整棵右子树是满二叉树,层数为h-l-1. 同(2.1),整体为2^(h - l - 1) -1 + 1+bs(node.left, l + 1, h)

  (3)复杂度分析。 每一层只会选择一个节点node进行bs的递归过程,所以调用bs函数的次数为O(h)

           每次调用bs函数时,都会查看node右子树的左子节点,所以会遍历O(h)个节点,因此总的复杂度为O(h^2)

class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) return 0;
        return bs(root, 1, mostLeftLevel(root, 1));
    }
    
    // 返回以node为根的完全二叉树的节点数是多少
    private int bs(TreeNode node, int curLevel, int level) {
        if (curLevel == level) {
            return 1;
        }
        // 对应情况2.1
        if (mostLeftLevel(node.right, curLevel + 1) == level) {
//            return (int)Math.pow(2,level - curLevel) + bs(node.right, curLevel + 1, level);
            return (1 << (level - curLevel)) + bs(node.right, curLevel + 1, level);
        }else { // 对应情况2.2
//            return (int)Math.pow(2,level - 1 - curLevel) + bs(node.left, curLevel + 1, level);
            return (1 << (level - 1 - curLevel)) + bs(node.left, curLevel + 1, level);
        }
    }
    
    // 求出以node为根的树的最左节点的层数
    private int mostLeftLevel(TreeNode node, int start) {
        while (node != null) {
            node = node.left;
            start ++;
        }
        return start - 1;
    }
}
原文地址:https://www.cnblogs.com/HuangYJ/p/14171735.html