Given the root of a complete binary tree, determine the total number of nodes present in the tree.
In a complete binary tree:
Every level except possibly the last is completely filled.
Nodes in the last level are placed as far left as possible.
Example 1
Input:root = [1, 2, 3, 4, 5, 6]
Output:6
Explanation:
The binary tree contains a total of 6 nodes.
Example 2
Input:root = [1]
Output:1
Explanation:
The tree contains only its root node, so the total number of nodes is 1.
Brute Force Approach
The most direct way to count the nodes is to visit every node once.
For any non-null node, the total number of nodes in its subtree is:
1 + nodes in left subtree + nodes in right subtree
The 1 represents the current node, while the remaining two terms represent the nodes belonging to its left and right subtrees.
This method works for every binary tree and does not make use of the special structure of a complete binary tree. Therefore, even when an entire subtree is perfectly filled and its size could be calculated directly, every node inside it is still visited.
Algorithm
If the current node is
null,0is returned because no node is present in that subtree.The number of nodes in the left subtree is recursively calculated.
The number of nodes in the right subtree is recursively calculated.
1is added for the current node along with the counts obtained from both subtrees.The resulting count is returned to the parent recursive call.
Once the root has been processed, the returned value represents the total number of nodes in the tree.
Dry Run
Count Nodes in Binary Tree Brute Force Dry Run .png
Solution
#include <bits/stdc++.h>using namespace std;struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int value) { val = value; left = nullptr; right = nullptr; }};class Solution {public: // Counts every node by recursively // combining the left and right subtree counts. int countNodes(TreeNode* root) { if (root == nullptr) { return 0; } int leftCount = countNodes(root->left); int rightCount = countNodes(root->right); return 1 + leftCount + rightCount; }};int main() { TreeNode* root = new TreeNode(1); root->left = new TreeNode(2); root->right = new TreeNode(3); root->left->left = new TreeNode(4); root->left->right = new TreeNode(5); root->right->left = new TreeNode(6); Solution solution; cout << solution.countNodes(root) << endl; return 0;}Complexity Analysis
Let N be the number of nodes in the binary tree and H be the height of the tree.
Time Complexity: O(N), where N is the total number of nodes in the binary tree. Every node is visited exactly once.
Space Complexity: O(H), where H is the height of the binary tree, due to the recursion stack. Since the input is a complete binary tree, H = O(log N), so the auxiliary space becomes O(log N).
Optimal Approach
The structure of a complete binary tree can be used to avoid visiting every node.
For each subtree, two heights are calculated:
leftHeightrepresents the number of nodes encountered while repeatedly moving through left children from the current node.rightHeightrepresents the number of nodes encountered while repeatedly moving through right children from the current node.
If leftHeight and rightHeight are equal, the current subtree is a perfect binary tree.
A perfect binary tree with height H, where height represents the number of nodes or levels along the extreme path, contains:
2^H - 1
nodes.
Therefore, when equal heights are found, the entire subtree can be counted immediately without traversing every node inside it.
If the two heights are different, the current subtree is not perfect. Its left and right subtrees are then processed recursively.
Because the original tree is complete, many large subtrees are detected as perfect and counted directly, reducing the amount of traversal required.
Algorithm
If the current node is
null,0is returned because the subtree contains no nodes.The value of
leftHeightis calculated by repeatedly following left-child pointers from the current node.The value of
rightHeightis calculated by repeatedly following right-child pointers from the current node.If
leftHeightandrightHeightare equal, the subtree is identified as perfect and its node count is calculated directly as2^leftHeight - 1.If the two heights are different, the left and right subtrees are recursively processed because the current subtree cannot be counted directly using the perfect-tree formula.
In this case,
1 + countNodes(root->left) + countNodes(root->right)is returned, where1represents the current node and the recursive calls count the nodes in both subtrees.
Dry Run
Count Nodes in Binary Tree Optimal Approach Dry Run .png
Solution
#include <bits/stdc++.h>using namespace std;struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int value) { val = value; left = nullptr; right = nullptr; }};class Solution {private: // Measures the extreme left height // of the current subtree. int getLeftHeight(TreeNode* node) { int height = 0; // Following only left children gives // the extreme left height of this subtree. while (node != nullptr) { height++; node = node->left; } return height; } // Measures the extreme right height // of the current subtree. int getRightHeight(TreeNode* node) { int height = 0; // Following only right children gives // the extreme right height of this subtree. while (node != nullptr) { height++; node = node->right; } return height; }public: // Uses the complete-tree property to count // perfect subtrees without visiting every node. long long countNodes(TreeNode* root) { if (root == nullptr) { return 0; } int leftHeight = getLeftHeight(root); int rightHeight = getRightHeight(root); // Equal extreme heights mean this complete // subtree is a perfect binary tree. if (leftHeight == rightHeight) { // A perfect tree with leftHeight levels has // 2^leftHeight - 1 nodes. // Left shift computes 2^leftHeight. return (1LL << leftHeight) - 1; } // When the subtree is not perfect, both sides // are counted recursively along with the root. return 1 + countNodes(root->left) + countNodes(root->right); }};int main() { TreeNode* root = new TreeNode(1); root->left = new TreeNode(2); root->right = new TreeNode(3); root->left->left = new TreeNode(4); root->left->right = new TreeNode(5); root->right->left = new TreeNode(6); Solution solution; cout << solution.countNodes(root) << endl; return 0;}Complexity Analysis
Let N be the number of nodes in the complete binary tree and H be its height.
Time Complexity: O(log² N). The height of a complete binary tree is H = O(log N). At each recursive level, up to O(H) work is required to calculate leftHeight and rightHeight, while the recursion proceeds through at most O(H) levels. Therefore, the total time complexity is O(H²) = O(log² N).
Space Complexity: O(log N). The recursion depth is bounded by the height H of the complete binary tree, and H = O(log N).
Interview follow-up Questions
For a complete binary tree, if the extreme left and extreme right paths have the same height, all levels of that subtree must be completely filled. Therefore, the subtree is perfect.
Be the first to add a comment.