222.计算完全二叉树的节点数
标签: tree, binary-search, depth-first-search
难度: Easy
通过率: 68.18%
原题链接: https://leetcode.com/problems/count-complete-tree-nodes/description/
题目描述
给定一棵完全二叉树的根节点,返回树中节点的数量。
解题思路
完全二叉树的特性是除了最后一层,其余层都是满的且最后一层的节点靠左排列。由于完全二叉树这样特殊的性质,使得在一些子树中递归计算节点数可以更有效。步骤如下:
- 
首先,计算左子树和右子树的高度。如果左右子树高度相同,则左子树是满的,可以通过公式直接计算节点数:,再加上根节点即为左子树的所有节点数。 
- 
如果左右高度不同,说明右子树是个满的二叉树,高度为右子树高,再递归地计算左子树的节点数。这种情况则反过来计算右子树的节点数。 
- 
通过递归上述步骤,最终我们可以在 时间复杂度以内计算出整个二叉树节点的总数。 
代码实现
- Python
- C++
- JavaScript
- Java
# Definition for a binary tree node.
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        # 计算完全二叉树的高度
        def getHeight(node):
            if not node:
                return 0
            return 1 + getHeight(node.left)
        
        if not root:
            return 0
        left_height = getHeight(root.left)
        right_height = getHeight(root.right)
        if left_height == right_height:
            # 左子树是满的,直接计算,它有 2^left_height - 1 个节点,加上根节点
            return (1 << left_height) + self.countNodes(root.right)
        else:
            # 右子树是满的,直接计算,它有 2^right_height - 1 个节点,加上根节点
            return (1 << right_height) + self.countNodes(root.left)
// Definition for a binary tree node.
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
class Solution {
public:
    int countNodes(TreeNode* root) {
        // 计算完全二叉树的高度
        auto getHeight = [](TreeNode* node) {
            int height = 0;
            while (node) {
                height++;
                node = node->left;
            }
            return height;
        };
        if (!root) return 0;
        int left_height = getHeight(root->left);
        int right_height = getHeight(root->right);
        if (left_height == right_height) {
            // 左子树是满的,直接计算,它有 2^left_height - 1 个节点,加上根节点
            return (1 << left_height) + countNodes(root->right);
        } else {
            // 右子树是满的,直接计算,它有 2^right_height - 1   个节点,加上根节点
            return (1 << right_height) + countNodes(root->left);
        }
    }
};
// Definition for a binary tree node.
function TreeNode(val, left, right) {
    this.val = (val===undefined ? 0 : val);
    this.left = (left===undefined ? null : left);
    this.right = (right===undefined ? null : right);
}
/**
 * @param {TreeNode} root
 * @return {number}
 */
var countNodes = function(root) {
    // 计算完全二叉树的高度
    const getHeight = (node) => {
        if (!node) return 0;
        return 1 + getHeight(node.left);
    };
    if (!root) return 0;
    const leftHeight = getHeight(root.left);
    const rightHeight = getHeight(root.right);
    if (leftHeight === rightHeight) {
        // 左子树是满的,直接计算,它有 2^left_height - 1 个节点,加上根节点
        return (1 << leftHeight) + countNodes(root.right);
    } else {
        // 右子树是满的,直接计算,它有 2^right_height - 1 个节点,加上根节点
        return (1 << rightHeight) + countNodes(root.left);
    }
};
// Definition for a binary tree node.
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode() {}
    TreeNode(int val) { this.val = val; }
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}
class Solution {
    public int countNodes(TreeNode root) {
        // 计算完全二叉树的高度
        int getHeight(TreeNode node) {
            if (node == null) return 0;
            return 1 + getHeight(node.left);
        }
        if (root == null) return 0;
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        if (leftHeight == rightHeight) {
            // 左子树是满的,直接计算,它有 2^left_height - 1 个节点,加上根节点
            return (1 << leftHeight) + countNodes(root.right);
        } else {
            // 右子树是满的,直接计算,它有 2^right_height - 1 个节点,加上根节点
            return (1 << rightHeight) + countNodes(root.left);
        }
    }
}
复杂度分析
时间复杂度:,这是因为每次递归调用都涉及树的高度的计算,而完全二叉树的高度是 ,且递归调用可以在 内完成。
空间复杂度:,主要是递归调用使用的堆栈空间与树的高度相关。