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++ implementation of the approach #include <bits/stdc++.h> using namespace std;
// Node structure of the tree struct node {
int data;
struct node* left;
struct node* right;
}; // To create a new node struct 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 findPerfectBinaryTree struct 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-tree returnType 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 tree void inorderPrint(node* root)
{ if (root != NULL) {
inorderPrint(root->left);
cout << root->data << " " ;
inorderPrint(root->right);
}
} // Driver code int 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 implementation of the approach import java.util.*;
class GFG
{ // Node structure of the tree static class node
{ int data;
node left;
node right;
}; // To create a new node static 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 findPerfectBinaryTree static 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-tree static 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 tree static void inorderPrint(node root)
{ if (root != null )
{
inorderPrint(root.left);
System.out.print(root.data + " " );
inorderPrint(root.right);
}
} // Driver code public 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 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 node def newNode(data):
node = Node( 0 )
node.data = data
node.left = None
node.right = None
return node
# Structure for return type of # function findPerfectBinaryTree class 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-tree def 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 tree def inorderPrint(root):
if (root ! = None ) :
inorderPrint(root.left)
print (root.data, end = " " )
inorderPrint(root.right)
# Driver code # Create tree 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 ans = findPerfectBinaryTree(root)
# Height of the found sub-tree h = ans.height
print ( "Size : " , pow ( 2 , h) - 1 )
# Print the inorder traversal of the found sub-tree print ( "Inorder Traversal : " , end = " " )
inorderPrint(ans.rootTree) # This code is contributed by Arnab Kundu |
// C# implementation of the approach using System;
class GFG
{ // Node structure of the tree public class node
{ public int data;
public node left;
public node right;
}; // To create a new node static 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 findPerfectBinaryTree public 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-tree static 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 tree static void inorderPrint(node root)
{ if (root != null )
{
inorderPrint(root.left);
Console.Write(root.data + " " );
inorderPrint(root.right);
}
} // Driver code public 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 |
<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.