Find the largest Perfect Subtree in a given Binary Tree

Given a Binary Tree, the task is to find the size of largest Perfect sub-tree in the given Binary Tree.
Perfect Binary Tree – A Binary tree is Perfect Binary Tree in which all internal nodes have two children and all leaves are at the same level.
Examples:
Input:
1
/ \
2 3
/ \ /
4 5 6
Output:
Size : 3
Inorder Traversal : 4 2 5
The following sub-tree is the maximum size Perfect sub-tree
2
/ \
4 5
Input:
50
/ \
30 60
/ \ / \
5 20 45 70
/ \ / \
10 85 65 80
Output:
Size : 7
Inorder Traversal : 10 45 85 60 65 70 80
Approach: Simply traverse the tree in bottom up manner. Then on coming up in recursion from child to parent, we can pass information about sub-trees to the parent. The passed information can be used by the parent to do the Perfect Tree test (for parent node) only in constant time. A left sub-tree need to tell the parent whether it is a Perfect Binary Tree or not and also need to pass max height of the Perfect Binary Tree coming from left child. Similarly, the right sub-tree also needs to pass max height of Perfect Binary Tree coming from right child.
The sub-trees need to pass the following information up the tree for finding the largest Perfect sub-tree so that we can compare the maximum height with the parent’s data to check the Perfect Binary Tree property.
- There is a bool variable to check whether the left child or the right child sub-tree is Perfect or not.
- From left and right child calls in recursion we find out if parent sub-tree if Perfect or not by following 2 cases:
- If both left child and right child are perfect binary tree and have same heights then parent is also a Perfect Binary Tree with height plus one of its child.
- If the above case is not true then parent cannot be perfect binary tree and simply returns max size Perfect Binary Tree coming from left or right sub-tree by comparing their heights.
Below is the implementation of the above approach:
C++
// C++ implementation of the approach#include <bits/stdc++.h>using namespace std;// Node structure of the treestruct node { int data; struct node* left; struct node* right;};// To create a new nodestruct node* newNode(int data){ struct node* node = (struct node*)malloc(sizeof(struct node)); node->data = data; node->left = NULL; node->right = NULL; return node;};// Structure for return type of// function findPerfectBinaryTreestruct returnType { // To store if sub-tree is perfect or not bool isPerfect; // Height of the tree int height; // Root of biggest perfect sub-tree node* rootTree;};// Function to return the biggest// perfect binary sub-treereturnType findPerfectBinaryTree(struct node* root){ // Declaring returnType that // needs to be returned returnType rt; // If root is NULL then it is considered as // perfect binary tree of height 0 if (root == NULL) { rt.isPerfect = true; rt.height = 0; rt.rootTree = NULL; return rt; } // Recursive call for left and right child returnType lv = findPerfectBinaryTree(root->left); returnType rv = findPerfectBinaryTree(root->right); // If both left and right sub-trees are perfect and // there height is also same then sub-tree root // is also perfect binary subtree with height // plus one of its child sub-trees if (lv.isPerfect && rv.isPerfect && lv.height == rv.height) { rt.height = lv.height + 1; rt.isPerfect = true; rt.rootTree = root; return rt; } // Else this sub-tree cannot be a perfect binary tree // and simply return the biggest sized perfect sub-tree // found till now in the left or right sub-trees rt.isPerfect = false; rt.height = max(lv.height, rv.height); rt.rootTree = (lv.height > rv.height ? lv.rootTree : rv.rootTree); return rt;}// Function to print the inorder traversal of the treevoid inorderPrint(node* root){ if (root != NULL) { inorderPrint(root->left); cout << root->data << " "; inorderPrint(root->right); }}// Driver codeint main(){ // Create tree struct node* root = newNode(1); root->left = newNode(2); root->right = newNode(3); root->left->left = newNode(4); root->left->right = newNode(5); root->right->left = newNode(6); // Get the biggest sizes perfect binary sub-tree struct returnType ans = findPerfectBinaryTree(root); // Height of the found sub-tree int h = ans.height; cout << "Size : " << pow(2, h) - 1 << endl; // Print the inorder traversal of the found sub-tree cout << "Inorder Traversal : "; inorderPrint(ans.rootTree); return 0;} |
Java
// Java implementation of the approachimport java.util.*;class GFG { // Node structure of the treestatic class node{ int data; node left; node right;};// To create a new nodestatic node newNode(int data){ node node = new node(); node.data = data; node.left = null; node.right = null; return node;};// Structure for return type of// function findPerfectBinaryTreestatic class returnType { // To store if sub-tree is perfect or not boolean isPerfect; // Height of the tree int height; // Root of biggest perfect sub-tree node rootTree;};// Function to return the biggest// perfect binary sub-treestatic returnType findPerfectBinaryTree(node root){ // Declaring returnType that // needs to be returned returnType rt = new returnType(); // If root is null then it is considered as // perfect binary tree of height 0 if (root == null) { rt.isPerfect = true; rt.height = 0; rt.rootTree = null; return rt; } // Recursive call for left and right child returnType lv = findPerfectBinaryTree(root.left); returnType rv = findPerfectBinaryTree(root.right); // If both left and right sub-trees are perfect and // there height is also same then sub-tree root // is also perfect binary subtree with height // plus one of its child sub-trees if (lv.isPerfect && rv.isPerfect && lv.height == rv.height) { rt.height = lv.height + 1; rt.isPerfect = true; rt.rootTree = root; return rt; } // Else this sub-tree cannot be a perfect binary tree // and simply return the biggest sized perfect sub-tree // found till now in the left or right sub-trees rt.isPerfect = false; rt.height = Math.max(lv.height, rv.height); rt.rootTree = (lv.height > rv.height ? lv.rootTree : rv.rootTree); return rt;}// Function to print the // inorder traversal of the treestatic void inorderPrint(node root){ if (root != null) { inorderPrint(root.left); System.out.print(root.data + " "); inorderPrint(root.right); }}// Driver codepublic static void main(String[] args) { // Create tree node root = newNode(1); root.left = newNode(2); root.right = newNode(3); root.left.left = newNode(4); root.left.right = newNode(5); root.right.left = newNode(6); // Get the biggest sizes perfect binary sub-tree returnType ans = findPerfectBinaryTree(root); // Height of the found sub-tree int h = ans.height; System.out.println("Size : " + (Math.pow(2, h) - 1)); // Print the inorder traversal of the found sub-tree System.out.print("Inorder Traversal : "); inorderPrint(ans.rootTree);}} // This code is contributed by 29AjayKumar |
Python3
# Python3 implementation of above approach# Tree node class Node: def __init__(self, data): self.data = data self.left = None self.right = None# To create a new nodedef newNode(data): node = Node(0) node.data = data node.left = None node.right = None return node# Structure for return type of# function findPerfectBinaryTreeclass returnType: def __init__(self): # To store if sub-tree is perfect or not isPerfect = 0 # Height of the tree height = 0 # Root of biggest perfect sub-tree rootTree = 0# Function to return the biggest# perfect binary sub-treedef findPerfectBinaryTree(root): # Declaring returnType that # needs to be returned rt = returnType() # If root is None then it is considered as # perfect binary tree of height 0 if (root == None) : rt.isPerfect = True rt.height = 0 rt.rootTree = None return rt # Recursive call for left and right child lv = findPerfectBinaryTree(root.left) rv = findPerfectBinaryTree(root.right) # If both left and right sub-trees are perfect and # there height is also same then sub-tree root # is also perfect binary subtree with height # plus one of its child sub-trees if (lv.isPerfect and rv.isPerfect and lv.height == rv.height) : rt.height = lv.height + 1 rt.isPerfect = True rt.rootTree = root return rt # Else this sub-tree cannot be a perfect binary tree # and simply return the biggest sized perfect sub-tree # found till now in the left or right sub-trees rt.isPerfect = False rt.height = max(lv.height, rv.height) if (lv.height > rv.height ): rt.rootTree = lv.rootTree else : rt.rootTree = rv.rootTree return rt# Function to print the inorder traversal of the treedef inorderPrint(root): if (root != None) : inorderPrint(root.left) print (root.data, end = " ") inorderPrint(root.right) # Driver code# Create treeroot = newNode(1)root.left = newNode(2)root.right = newNode(3)root.left.left = newNode(4)root.left.right = newNode(5)root.right.left = newNode(6)# Get the biggest sizes perfect binary sub-treeans = findPerfectBinaryTree(root)# Height of the found sub-treeh = ans.heightprint ("Size : " , pow(2, h) - 1)# Print the inorder traversal of the found sub-treeprint ("Inorder Traversal : ", end = " ")inorderPrint(ans.rootTree)# This code is contributed by Arnab Kundu |
C#
// C# implementation of the approachusing System;class GFG { // Node structure of the treepublic class node{ public int data; public node left; public node right;};// To create a new nodestatic node newNode(int data){ node node = new node(); node.data = data; node.left = null; node.right = null; return node;}// Structure for return type of// function findPerfectBinaryTreepublic class returnType { // To store if sub-tree is perfect or not public bool isPerfect; // Height of the tree public int height; // Root of biggest perfect sub-tree public node rootTree;};// Function to return the biggest// perfect binary sub-treestatic returnType findPerfectBinaryTree(node root){ // Declaring returnType that // needs to be returned returnType rt = new returnType(); // If root is null then it is considered as // perfect binary tree of height 0 if (root == null) { rt.isPerfect = true; rt.height = 0; rt.rootTree = null; return rt; } // Recursive call for left and right child returnType lv = findPerfectBinaryTree(root.left); returnType rv = findPerfectBinaryTree(root.right); // If both left and right sub-trees are perfect and // there height is also same then sub-tree root // is also perfect binary subtree with height // plus one of its child sub-trees if (lv.isPerfect && rv.isPerfect && lv.height == rv.height) { rt.height = lv.height + 1; rt.isPerfect = true; rt.rootTree = root; return rt; } // Else this sub-tree cannot be a perfect binary tree // and simply return the biggest sized perfect sub-tree // found till now in the left or right sub-trees rt.isPerfect = false; rt.height = Math.Max(lv.height, rv.height); rt.rootTree = (lv.height > rv.height ? lv.rootTree : rv.rootTree); return rt;}// Function to print the // inorder traversal of the treestatic void inorderPrint(node root){ if (root != null) { inorderPrint(root.left); Console.Write(root.data + " "); inorderPrint(root.right); }}// Driver codepublic static void Main(String[] args) { // Create tree node root = newNode(1); root.left = newNode(2); root.right = newNode(3); root.left.left = newNode(4); root.left.right = newNode(5); root.right.left = newNode(6); // Get the biggest sizes perfect binary sub-tree returnType ans = findPerfectBinaryTree(root); // Height of the found sub-tree int h = ans.height; Console.WriteLine("Size : " + (Math.Pow(2, h) - 1)); // Print the inorder traversal of the found sub-tree Console.Write("Inorder Traversal : "); inorderPrint(ans.rootTree);}}// This code is contributed by Princi Singh |
Javascript
<script> // JavaScript program to print postorder // traversal iteratively // Node structure of the tree class node { constructor(data) { this.left = null; this.right = null; this.data = data; } } // To create a new node function newNode(data) { let Node = new node(data); return Node; } // Structure for return type of // function findPerfectBinaryTree class returnType { constructor(data) { this.isPerfect; this.height; this.rootTree; } } // Function to return the biggest // perfect binary sub-tree function findPerfectBinaryTree(root) { // Declaring returnType that // needs to be returned let rt = new returnType(); // If root is null then it is considered as // perfect binary tree of height 0 if (root == null) { rt.isPerfect = true; rt.height = 0; rt.rootTree = null; return rt; } // Recursive call for left and right child let lv = findPerfectBinaryTree(root.left); let rv = findPerfectBinaryTree(root.right); // If both left and right sub-trees are perfect and // there height is also same then sub-tree root // is also perfect binary subtree with height // plus one of its child sub-trees if (lv.isPerfect && rv.isPerfect && lv.height == rv.height) { rt.height = lv.height + 1; rt.isPerfect = true; rt.rootTree = root; return rt; } // Else this sub-tree cannot be a perfect binary tree // and simply return the biggest sized perfect sub-tree // found till now in the left or right sub-trees rt.isPerfect = false; rt.height = Math.max(lv.height, rv.height); rt.rootTree = (lv.height > rv.height ? lv.rootTree : rv.rootTree); return rt; } // Function to print the // inorder traversal of the tree function inorderPrint(root) { if (root != null) { inorderPrint(root.left); document.write(root.data + " "); inorderPrint(root.right); } } // Create tree let root = newNode(1); root.left = newNode(2); root.right = newNode(3); root.left.left = newNode(4); root.left.right = newNode(5); root.right.left = newNode(6); // Get the biggest sizes perfect binary sub-tree let ans = findPerfectBinaryTree(root); // Height of the found sub-tree let h = ans.height; document.write("Size : " + (Math.pow(2, h) - 1) + "</br>"); // Print the inorder traversal of the found sub-tree document.write("Inorder Traversal : "); inorderPrint(ans.rootTree);</script> |
Size : 3 Inorder Traversal : 4 2 5
Time Complexity: O(n)
We are traversing the entire tree once.
Space Complexity: O(h)
For a given tree, we are storing the height of the tree in the returnType.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 zambiatek!


