LeetCodee

222. Count Complete Tree Nodes

Jump to Solution: Python Java C++ JavaScript C#

Problem Description

Given the root of a complete binary tree, return the number of nodes in the tree.

According to Wikipedia, every level, except possibly the last, is completely filled in a complete binary tree, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.

Design an algorithm that runs in less than O(n) time complexity.

Example 1:

Input: root = [1,2,3,4,5,6]
Output: 6

Example 2:

Input: root = []
Output: 0

Example 3:

Input: root = [1]
Output: 1

Constraints:

  • The number of nodes in the tree is in the range [0, 5 * 10^4]
  • 0 <= Node.val <= 5 * 10^4
  • The tree is guaranteed to be complete

Solution

Python Solution

class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
            
        # Get the height of left and right subtree
        left_height = self.getLeftHeight(root)
        right_height = self.getRightHeight(root)
        
        # If heights are equal, use formula 2^h - 1
        if left_height == right_height:
            return (1 << left_height) - 1
            
        # Otherwise, recursively count nodes
        return 1 + self.countNodes(root.left) + self.countNodes(root.right)
        
    def getLeftHeight(self, node):
        height = 0
        while node:
            height += 1
            node = node.left
        return height
        
    def getRightHeight(self, node):
        height = 0
        while node:
            height += 1
            node = node.right
        return height

Time Complexity: O(log²n)

We traverse down the tree O(log n) times, and at each step we calculate heights which takes O(log n).

Space Complexity: O(log n)

Due to the recursion stack.

Java Solution

class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        // Get the height of left and right subtree
        int leftHeight = getLeftHeight(root);
        int rightHeight = getRightHeight(root);
        
        // If heights are equal, use formula 2^h - 1
        if (leftHeight == rightHeight) {
            return (1 << leftHeight) - 1;
        }
        
        // Otherwise, recursively count nodes
        return 1 + countNodes(root.left) + countNodes(root.right);
    }
    
    private int getLeftHeight(TreeNode node) {
        int height = 0;
        while (node != null) {
            height++;
            node = node.left;
        }
        return height;
    }
    
    private int getRightHeight(TreeNode node) {
        int height = 0;
        while (node != null) {
            height++;
            node = node.right;
        }
        return height;
    }
}

Time Complexity: O(log²n)

We traverse down the tree O(log n) times, and at each step we calculate heights which takes O(log n).

Space Complexity: O(log n)

Due to the recursion stack.

C++ Solution

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (!root) {
            return 0;
        }
        
        // Get the height of left and right subtree
        int leftHeight = getLeftHeight(root);
        int rightHeight = getRightHeight(root);
        
        // If heights are equal, use formula 2^h - 1
        if (leftHeight == rightHeight) {
            return (1 << leftHeight) - 1;
        }
        
        // Otherwise, recursively count nodes
        return 1 + countNodes(root->left) + countNodes(root->right);
    }
    
private:
    int getLeftHeight(TreeNode* node) {
        int height = 0;
        while (node) {
            height++;
            node = node->left;
        }
        return height;
    }
    
    int getRightHeight(TreeNode* node) {
        int height = 0;
        while (node) {
            height++;
            node = node->right;
        }
        return height;
    }
};

Time Complexity: O(log²n)

We traverse down the tree O(log n) times, and at each step we calculate heights which takes O(log n).

Space Complexity: O(log n)

Due to the recursion stack.

JavaScript Solution

/**
 * 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) {
    if (!root) {
        return 0;
    }
    
    // Get the height of left and right subtree
    const leftHeight = getLeftHeight(root);
    const rightHeight = getRightHeight(root);
    
    // If heights are equal, use formula 2^h - 1
    if (leftHeight === rightHeight) {
        return (1 << leftHeight) - 1;
    }
    
    // Otherwise, recursively count nodes
    return 1 + countNodes(root.left) + countNodes(root.right);
};

function getLeftHeight(node) {
    let height = 0;
    while (node) {
        height++;
        node = node.left;
    }
    return height;
}

function getRightHeight(node) {
    let height = 0;
    while (node) {
        height++;
        node = node.right;
    }
    return height;
}

Time Complexity: O(log²n)

We traverse down the tree O(log n) times, and at each step we calculate heights which takes O(log n).

Space Complexity: O(log n)

Due to the recursion stack.

C# Solution

public class Solution {
    public int CountNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        // Get the height of left and right subtree
        int leftHeight = GetLeftHeight(root);
        int rightHeight = GetRightHeight(root);
        
        // If heights are equal, use formula 2^h - 1
        if (leftHeight == rightHeight) {
            return (1 << leftHeight) - 1;
        }
        
        // Otherwise, recursively count nodes
        return 1 + CountNodes(root.left) + CountNodes(root.right);
    }
    
    private int GetLeftHeight(TreeNode node) {
        int height = 0;
        while (node != null) {
            height++;
            node = node.left;
        }
        return height;
    }
    
    private int GetRightHeight(TreeNode node) {
        int height = 0;
        while (node != null) {
            height++;
            node = node.right;
        }
        return height;
    }
}

Time Complexity: O(log²n)

We traverse down the tree O(log n) times, and at each step we calculate heights which takes O(log n).

Space Complexity: O(log n)

Due to the recursion stack.

Approach Explanation

The solution takes advantage of the properties of a complete binary tree to achieve better than O(n) time complexity. Here's how it works:

  1. For a complete binary tree:
    • If the left and right subtree heights are equal, the tree is a perfect binary tree
    • For a perfect binary tree of height h, we can calculate the number of nodes using the formula 2^h - 1
    • If the heights are not equal, we need to recursively count nodes in both subtrees
  2. The algorithm:
    • Calculate the height of the leftmost path and rightmost path
    • If they're equal, use the formula 2^h - 1
    • Otherwise, recursively count nodes in left and right subtrees

The key insight is that we don't need to visit every node. By checking if subtrees are perfect binary trees, we can calculate their node count in O(1) time using the formula. This leads to a time complexity of O(log²n) instead of O(n).