: , , .
With the current number of nodes and height, you can calculate the root number of nodes and height through information related to its direct children, taking into account the relationship between child heights and if they are perfect subtrees or not.
The solution is O (n) time complexity and O (h) spatial complexity (the stack of function calls corresponds to the root through a unique path to the current node).
Here is the Python code for this solution, and you can find the full point with examples here :
from collections import namedtuple
class BTN():
def __init__(self, data=None, left=None, right=None):
self.data = data
self.left = left
self.right = right
def max_nodes_per_height(height: int) -> int:
return 2**(height + 1) - 1
def height_largest_complete_subtree(root: BTN) -> int:
CompleteInformation = namedtuple('CompleteInformation', ['height', 'num_nodes', 'max_height'])
def height_largest_complete_subtree_aux(root: BTN) -> CompleteInformation:
if (root is None):
return CompleteInformation(-1, 0, 0)
left_complete_info = height_largest_complete_subtree_aux(root.left)
right_complete_info = height_largest_complete_subtree_aux(root.right)
left_height = left_complete_info.height
right_height = right_complete_info.height
if (left_height == right_height):
if (left_complete_info.num_nodes == max_nodes_per_height(left_height)):
new_height = left_height + 1
new_num_nodes = left_complete_info.num_nodes + right_complete_info.num_nodes + 1
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
else:
new_height = left_height
new_num_nodes = max_nodes_per_height(left_height)
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
elif (left_height > right_height):
if (max_nodes_per_height(right_height) == right_complete_info.num_nodes):
new_height = right_height + 2
new_num_nodes = min(left_complete_info.num_nodes, max_nodes_per_height(right_height + 1)) + right_complete_info.num_nodes + 1
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
else:
new_height = right_height + 1
new_num_nodes = max_nodes_per_height(right_height) + right_complete_info.num_nodes + 1
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
elif (left_height < right_height):
if (left_complete_info.num_nodes == max_nodes_per_height(left_height)):
new_height = left_height + 1
new_num_nodes = left_complete_info.num_nodes + max_nodes_per_height(left_height) + 1
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
else:
new_height = left_height
new_num_nodes = (max_nodes_per_height(left_height - 1) * 2) + 1
return CompleteInformation(new_height,
new_num_nodes,
max(new_height, max(left_complete_info.max_height, right_complete_info.max_height))
)
return height_largest_complete_subtree_aux(root).max_height