Question
Given a complete binary tree, count the number of nodes.
Note:
Definition of a complete binary tree from Wikipedia: In a complete binary tree every level, except possibly the last, is completely filled, 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.
Example:
Input:
1
/ \
2 3
/ \ /
4 5 6
Output: 6
DFS Solution
DFS until find the rightmost element in the last row. \(O(n)\).
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def countNodes(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if root is None:
return 0
stack = list()
node = root
max_lvl = 1
while node.left is not None:
if node.right is None:
return 2 ** max_lvl
else:
stack.append((max_lvl + 1, node.right))
node = node.left
max_lvl += 1
lvl_count = 1
while len(stack) > 0:
lvl, node = stack.pop()
if lvl == max_lvl:
lvl_count += 1
elif lvl == max_lvl - 1:
if node.left is None:
return 2 ** (max_lvl - 1) - 1 + lvl_count
else:
lvl_count += 1
if node.right is None:
return 2 ** (max_lvl - 1) - 1 + lvl_count
else:
lvl_count += 1
else:
stack.append((lvl + 1, node.right))
stack.append((lvl + 1, node.left))
return 2 ** max_lvl - 1
Divide-and-Conquer Solution
The height of a tree can be found by just going left. Let a single node tree have height 1. Find the height h of the whole tree. If the whole tree is empty, i.e., has height 0.
Check whether the height of the right subtree is just one less than that of the whole tree, meaning left and right subtree have the same height.
- If yes, then the last node on the last tree row is in the right subtree and the left subtree is a full tree of height
h-1
. So we take the \(2^{h-1}-1\) nodes of the left subtree plus the 1 root node plus recursively the number of nodes in the right subtree. - If no, then the last node on the last tree row is in the left subtree and the right subtree is a full tree of height
h-2
. So we take the \(2^{h-2}-1\) nodes of the right subtree plus the 1 root node plus recursively the number of nodes in the left subtree.
Since I halve the tree in every recursive step, I have \(O(log(n))\) steps. Finding a height costs \(O(log(n))\). So overall \(O(log(n)^2)\).
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def countNodes(self, root):
"""
:type root: TreeNode
:rtype: int
"""
if root is None:
return 0
tree_height = self.height(root)
if tree_height == 1:
return 1
if self.height(root.right) == tree_height - 1:
return (1 << (tree_height - 1)) + self.countNodes(root.right)
else:
return (1 << (tree_height - 2)) + self.countNodes(root.left)
return res
def height(self, root):
lvl = 0
while root is not None:
lvl += 1
root = root.left
return lvl