Find the maximum element of every subtree of a Binary Tree
Last Updated :
12 Feb, 2023
Given a Binary Tree, find the maximum element of every subtree of it.
Examples :
Input :
1
/ \
2 3
/ \ / \
4 5 6 7
Output : [4, 5, 5, 7, 6, 7, 7]
Explanation:
The maximum element of the subtree rooted at node 4 is 4.
The maximum element of the subtree rooted at node 2 is 5.
The maximum element of the subtree rooted at node 5 is 5.
The maximum element of the subtree rooted at node 1 is 7.
The maximum element of the subtree rooted at node 6 is 6.
The maximum element of the subtree rooted at node 3 is 7.
The maximum element of the subtree rooted at node 7 is 7.
Input :
5
/ \
3 8
/ \ / \
2 4 7 9
Output : [2, 4, 4, 9, 7, 9, 9]
Explanation:
The maximum element of the subtree rooted at node 2 is 2.
The maximum element of the subtree rooted at node 3 is 4.
The maximum element of the subtree rooted at node 4 is 4.
The maximum element of the subtree rooted at node 5 is 9.
The maximum element of the subtree rooted at node 7 is 7.
The maximum element of the subtree rooted at node 8 is 9.
The maximum element of the subtree rooted at node 9 is 9.
Methods:
There are some methods to solve the problem of finding the maximum element of every subtree in a binary tree:-
Method 1: Using Recursion
Algorithm:
- Create a Node structure to store a binary tree node with data, left, and right pointer
- Create a vector “ans” with 10 (greater than max element of the tree) elements with initial values INT_MIN.
- Implement a function “recMaxSubtreeElement” to traverse the binary tree in a post-order fashion.
- In the function, if the node is NULL, return from the function.
- If the left child of the node exists, call the “recMaxSubtreeElement” function on the left child and store the maximum value in the “left” variable.
- If the right child of the node exists, call the “recMaxSubtreeElement” function on the right child and store the maximum value in the “right” variable.
- Store the maximum value among the node’s data, left child, and right child in the “ans” vector at the index equal to the node’s data.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
struct Node {
int data;
Node* left;
Node* right;
Node( int x)
: data(x), left(NULL), right(NULL)
{
}
};
vector< int > ans(10, INT_MIN);
void recMaxSubtreeElement(Node* node)
{
if (!node)
return ;
int left = INT_MIN, right = INT_MIN;
if (node->left) {
recMaxSubtreeElement(node->left);
left = ans[node->left->data];
}
if (node->right) {
recMaxSubtreeElement(node->right);
right = ans[node->right->data];
}
ans[node->data] = (max(left, max(right, node->data)));
}
int main()
{
Node* root = new Node(5);
root->left = new Node(3);
root->right = new Node(8);
root->left->left = new Node(2);
root->left->right = new Node(4);
root->right->left = new Node(7);
root->right->right = new Node(9);
recMaxSubtreeElement(root);
for ( int i = 1; i < ans.size(); i++) {
if (ans[i] != INT_MIN)
cout << ans[i] << " " ;
}
cout << endl;
return 0;
}
|
Java
import java.util.Arrays;
class Node {
int data;
Node left;
Node right;
Node( int x)
{
data = x;
left = right = null ;
}
}
class GFG {
static int [] ans = new int [ 10 ];
static void recMaxSubtreeElement(Node node)
{
if (node == null ) {
return ;
}
int left = Integer.MIN_VALUE, right
= Integer.MIN_VALUE;
if (node.left != null ) {
recMaxSubtreeElement(node.left);
left = ans[node.left.data];
}
if (node.right != null ) {
recMaxSubtreeElement(node.right);
right = ans[node.right.data];
}
ans[node.data]
= Math.max(left, Math.max(right, node.data));
}
public static void main(String[] args)
{
Node root = new Node( 5 );
root.left = new Node( 3 );
root.right = new Node( 8 );
root.left.left = new Node( 2 );
root.left.right = new Node( 4 );
root.right.left = new Node( 7 );
root.right.right = new Node( 9 );
Arrays.fill(ans, Integer.MIN_VALUE);
recMaxSubtreeElement(root);
for ( int i = 1 ; i < ans.length; i++) {
if (ans[i] != Integer.MIN_VALUE) {
System.out.print(ans[i] + " " );
}
}
System.out.println();
}
}
|
Python3
class Node:
def __init__( self , x):
self .data = x
self .left = None
self .right = None
ans = [ float ( "-inf" )] * 10
def recMaxSubtreeElement(node):
if node is None :
return
left = float ( "-inf" )
right = float ( "-inf" )
if node.left:
recMaxSubtreeElement(node.left)
left = ans[node.left.data]
if node.right:
recMaxSubtreeElement(node.right)
right = ans[node.right.data]
ans[node.data] = ( max (left, max (right, node.data)))
root = Node( 5 )
root.left = Node( 3 )
root.right = Node( 8 )
root.left.left = Node( 2 )
root.left.right = Node( 4 )
root.right.left = Node( 7 )
root.right.right = Node( 9 )
recMaxSubtreeElement(root)
for i in range ( 1 , len (ans)):
if ans[i] ! = float ( "-inf" ):
print (ans[i], end = " " )
print ()
|
C#
using System;
using System.Collections.Generic;
class Node {
public int data;
public Node left;
public Node right;
public Node( int x)
{
data = x;
left = null ;
right = null ;
}
}
class BinaryTree {
List< int > ans = new List< int >();
public void RecMaxSubtreeElement(Node node)
{
if (node == null ) {
return ;
}
int left = int .MinValue, right = int .MinValue;
if (node.left != null ) {
RecMaxSubtreeElement(node.left);
left = ans[node.left.data];
}
if (node.right != null ) {
RecMaxSubtreeElement(node.right);
right = ans[node.right.data];
}
if (ans.Count <= node.data) {
ans.AddRange( new int [node.data - ans.Count + 1]);
}
ans[node.data] = Math.Max(left, Math.Max(right, node.data));
}
static void Main( string [] args)
{
Node root = new Node(5);
root.left = new Node(3);
root.right = new Node(8);
root.left.left = new Node(2);
root.left.right = new Node(4);
root.right.left = new Node(7);
root.right.right = new Node(9);
BinaryTree bt = new BinaryTree();
bt.RecMaxSubtreeElement(root);
for ( int i = 1; i < bt.ans.Count; i++) {
if (bt.ans[i] != int .MinValue && bt.ans[i] != 0)
Console.Write(bt.ans[i] + " " );
}
Console.WriteLine();
}
}
|
Javascript
<script>
class Node {
constructor(x) {
this .data = x;
this .left = null ;
this .right = null ;
}
}
let ans = new Array(10).fill(Number.MIN_SAFE_INTEGER);
function recMaxSubtreeElement(node) {
if (!node) return ;
let left = Number.MIN_SAFE_INTEGER,
right = Number.MIN_SAFE_INTEGER;
if (node.left) {
recMaxSubtreeElement(node.left);
left = ans[node.left.data];
}
if (node.right) {
recMaxSubtreeElement(node.right);
right = ans[node.right.data];
}
ans[node.data] = Math.max(left, Math.max(right, node.data));
}
let root = new Node(5);
root.left = new Node(3);
root.right = new Node(8);
root.left.left = new Node(2);
root.left.right = new Node(4);
root.right.left = new Node(7);
root.right.right = new Node(9);
recMaxSubtreeElement(root);
for (let i = 1; i < ans.length; i++) {
if (ans[i] !== Number.MIN_SAFE_INTEGER) document.write(ans[i] + " " );
}
</script>
|
Time Complexity: O(2N), where N is the number of nodes in the tree.
Auxiliary Space: O(N)
Method 2: Using Dynamic Programming(DP)
Algorithm:
- Create an unordered_map dp to store the maximum element of every subtree.
- Create a function dpMaxSubtreeElement to find the maximum element of every subtree of the binary tree using Dynamic Programming.
- The function takes two arguments: node and dp (unordered_map).
- Check if node is present in the dp, return the stored maximum element.
- If node is not present in the dp, initialize maxElement to INT_MIN.
- If node has a left child, update maxElement to the maximum of maxElement and the maximum element of the left subtree.
- If node has a right child, update maxElement to the maximum of maxElement and the maximum element of the right subtree.
- Store max(maxElement, node->data) in dp[node].
- Return dp[node].
- Create a function print_in_inorder to print the maximum element of every subtree in inorder.
- The function takes two arguments: node and dp (unordered_map).
- If node is NULL, return.
- Recursively traverse the left subtree and print the maximum element of the subtree.
- Recursively traverse the right subtree and print the maximum element of the subtree.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
struct Node {
int data;
Node* left;
Node* right;
Node( int x)
: data(x), left(NULL), right(NULL)
{
}
};
int dpMaxSubtreeElement(Node* node,
unordered_map<Node*, int >& dp)
{
if (dp.count(node))
return dp[node];
int maxElement = INT_MIN;
if (node->left) {
maxElement
= max(maxElement,
dpMaxSubtreeElement(node->left, dp));
}
if (node->right) {
maxElement
= max(maxElement,
dpMaxSubtreeElement(node->right, dp));
}
dp[node] = max(maxElement, node->data);
return dp[node];
}
void print_in_inorder(Node* node,
unordered_map<Node*, int >& dp)
{
if (node == NULL)
return ;
print_in_inorder(node->left, dp);
cout << dp[node] << " " ;
print_in_inorder(node->right, dp);
}
int main()
{
Node* root = new Node(5);
root->left = new Node(3);
root->right = new Node(8);
root->left->left = new Node(2);
root->left->right = new Node(4);
root->right->left = new Node(7);
root->right->right = new Node(9);
unordered_map<Node*, int > dp;
int maxElement = dpMaxSubtreeElement(root, dp);
print_in_inorder(root, dp);
return 0;
}
|
Java
import java.util.*;
class Node {
int data;
Node left;
Node right;
Node( int x)
{
this .data = x;
this .left = null ;
this .right = null ;
}
};
public class GFG {
static int
dpMaxSubtreeElement(Node node,
HashMap<Node, Integer> dp)
{
if (dp.containsKey(node))
return dp.get(node);
int maxElement = Integer.MIN_VALUE;
if (node.left != null ) {
maxElement = Math.max(
maxElement,
dpMaxSubtreeElement(node.left, dp));
}
if (node.right != null ) {
maxElement = Math.max(
maxElement,
dpMaxSubtreeElement(node.right, dp));
}
dp.put(node, Math.max(maxElement, node.data));
return dp.get(node);
}
static void print_in_inorder(Node node,
HashMap<Node, Integer> dp)
{
if (node == null )
return ;
print_in_inorder(node.left, dp);
System.out.print(dp.get(node)
+ " " );
print_in_inorder(node.right, dp);
}
public static void main(String[] args)
{
Node root = new Node( 5 );
root.left = new Node( 3 );
root.right = new Node( 8 );
root.left.left = new Node( 2 );
root.left.right = new Node( 4 );
root.right.left = new Node( 7 );
root.right.right = new Node( 9 );
HashMap<Node, Integer> dp
= new HashMap<Node, Integer>();
int maxElement = dpMaxSubtreeElement(root, dp);
print_in_inorder(root, dp);
}
}
|
Python3
class Node:
def __init__( self , x):
self .data = x
self .left = None
self .right = None
def dpMaxSubtreeElement(node, dp):
if node in dp:
return dp[node]
maxElement = float ( '-inf' )
if node.left:
maxElement = max (maxElement, dpMaxSubtreeElement(node.left, dp))
if node.right:
maxElement = max (maxElement, dpMaxSubtreeElement(node.right, dp))
dp[node] = max (maxElement, node.data)
return dp[node]
def print_in_inorder(node, dp):
if node = = None :
return
print_in_inorder(node.left, dp)
print (dp[node], end = " " )
print_in_inorder(node.right, dp)
if __name__ = = '__main__' :
root = Node( 5 )
root.left = Node( 3 )
root.right = Node( 8 )
root.left.left = Node( 2 )
root.left.right = Node( 4 )
root.right.left = Node( 7 )
root.right.right = Node( 9 )
dp = {}
maxElement = dpMaxSubtreeElement(root, dp)
print_in_inorder(root, dp)
|
C#
using System;
using System.Collections.Generic;
class Node {
public int data;
public Node left;
public Node right;
public Node( int x)
{
data = x;
left = null ;
right = null ;
}
}
class Program {
static Dictionary<Node, int > dp
= new Dictionary<Node, int >();
static int DpMaxSubtreeElement(Node node)
{
if (dp.ContainsKey(node))
return dp[node];
int maxElement = int .MinValue;
if (node.left != null ) {
maxElement = Math.Max(
maxElement, DpMaxSubtreeElement(node.left));
}
if (node.right != null ) {
maxElement
= Math.Max(maxElement,
DpMaxSubtreeElement(node.right));
}
dp[node] = Math.Max(maxElement, node.data);
return dp[node];
}
static void PrintInInorder(Node node)
{
if (node == null )
return ;
PrintInInorder(node.left);
Console.Write(dp[node] + " " );
PrintInInorder(node.right);
}
static void Main( string [] args)
{
Node root = new Node(5);
root.left = new Node(3);
root.right = new Node(8);
root.left.left = new Node(2);
root.left.right = new Node(4);
root.right.left = new Node(7);
root.right.right = new Node(9);
int maxElement = DpMaxSubtreeElement(root);
PrintInInorder(root);
}
}
|
Javascript
<script>
class Node {
constructor(data) {
this .data = data;
this .left = null ;
this .right = null ;
}
}
function dpMaxSubtreeElement(node, dp = new Map()) {
if (dp.has(node)) return dp.get(node);
let maxElement = Number.MIN_SAFE_INTEGER;
if (node.left) {
maxElement = Math.max(maxElement, dpMaxSubtreeElement(node.left, dp));
}
if (node.right) {
maxElement = Math.max(maxElement, dpMaxSubtreeElement(node.right, dp));
}
dp.set(node, Math.max(maxElement, node.data));
return dp.get(node);
}
function print_in_inorder(node, dp) {
if (!node) return ;
print_in_inorder(node.left, dp);
document.write(dp.get(node)+ " " );
print_in_inorder(node.right, dp);
}
const root = new Node(5);
root.left = new Node(3);
root.right = new Node(8);
root.left.left = new Node(2);
root.left.right = new Node(4);
root.right.left = new Node(7);
root.right.right = new Node(9);
const dp = new Map();
const maxElement = dpMaxSubtreeElement(root, dp);
print_in_inorder(root, dp);
</script>
|
Time Complexity: O(N), where n is the number of nodes in the binary tree.
Auxiliary Space: O(N)
Complexity Analysis:
The time complexity of the above code is O(n), where n is the number of nodes in the binary tree. This is because the dpMaxSubtreeElement function visits each node of the binary tree exactly once, and the time required to process a node is proportional to the number of its children.
The space complexity of the above code is O(n), where n is the number of nodes in the binary tree. This is because the dp unordered_map stores the maximum element of each subtree, so the memory usage is proportional to the number of nodes in the binary tree.
Method 3: Depth-First Search (DFS)
Using the DFS approach, we can traverse the tree recursively. At each node, we compare the maximum element of the left and right subtrees and add the greater element to the list of maximum elements for the node. We then recursively traverse the left and right subtrees and repeat this process.
Algorithm:
- Create an empty list to store the maximum elements.
- Create a recursive function that takes a node and the list as arguments.
- Compare the maximum element of the left and right subtrees of the node, and store the maximum element to the list at the index of the current node’s data.
- Recursively call the function for the left and right children of the node.
- Repeat until the node is null.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
struct Node {
int data;
Node* left;
Node* right;
Node( int x)
: data(x), left(NULL), right(NULL)
{
}
};
int dfsMaxSubtreeElement(Node* node,
vector< int >& maxSubtreeElement)
{
if (node == NULL)
return 0;
int leftMax = dfsMaxSubtreeElement(node->left,
maxSubtreeElement);
int rightMax = dfsMaxSubtreeElement(node->right,
maxSubtreeElement);
int maxElement
= max(node->data, max(leftMax, rightMax));
maxSubtreeElement[node->data] = maxElement;
return maxElement;
}
int main()
{
Node* root = new Node(5);
root->left = new Node(3);
root->right = new Node(8);
root->left->left = new Node(2);
root->left->right = new Node(4);
root->right->left = new Node(7);
root->right->right = new Node(9);
vector< int > maxSubtreeElement(10, INT_MIN);
dfsMaxSubtreeElement(root, maxSubtreeElement);
int i = 0;
while (maxSubtreeElement[i] == INT_MIN)
i++;
cout << "[" << maxSubtreeElement[i];
for ( int j = i + 1; j < maxSubtreeElement.size(); j++) {
if (maxSubtreeElement[j] != INT_MIN)
cout << ", " << maxSubtreeElement[j];
}
cout << "]" << endl;
return 0;
}
|
Java
import java.util.*;
class Node {
int data;
Node left;
Node right;
Node( int x)
{
this .data = x;
this .left = null ;
this .right = null ;
}
}
public class Main {
static int dfsMaxSubtreeElement(
Node node, Map<Integer, Integer> maxSubtreeElement)
{
if (node == null )
return 0 ;
int leftMax = dfsMaxSubtreeElement(
node.left, maxSubtreeElement);
int rightMax = dfsMaxSubtreeElement(
node.right, maxSubtreeElement);
int maxElement = Math.max(
node.data, Math.max(leftMax, rightMax));
maxSubtreeElement.put(node.data, maxElement);
return maxElement;
}
public static void main(String[] args)
{
Node root = new Node( 5 );
root.left = new Node( 3 );
root.right = new Node( 8 );
root.left.left = new Node( 2 );
root.left.right = new Node( 4 );
root.right.left = new Node( 7 );
root.right.right = new Node( 9 );
Map<Integer, Integer> maxSubtreeElement
= new HashMap<>();
dfsMaxSubtreeElement(root, maxSubtreeElement);
int i = 0 ;
System.out.print( "[" );
for (Map.Entry<Integer, Integer> entry :
maxSubtreeElement.entrySet()) {
i++;
System.out.print(entry.getValue());
if (i != maxSubtreeElement.size())
System.out.print( ", " );
}
System.out.println( "]" );
}
}
|
Python3
class Node:
def __init__( self , x):
self .data = x
self .left = None
self .right = None
def dfsMaxSubtreeElement(node, maxSubtreeElement):
if node is None :
return 0
leftMax = dfsMaxSubtreeElement(node.left, maxSubtreeElement)
rightMax = dfsMaxSubtreeElement(node.right, maxSubtreeElement)
maxElement = max (node.data, max (leftMax, rightMax))
maxSubtreeElement[node.data] = maxElement
return maxElement
if __name__ = = "__main__" :
root = Node( 5 )
root.left = Node( 3 )
root.right = Node( 8 )
root.left.left = Node( 2 )
root.left.right = Node( 4 )
root.right.left = Node( 7 )
root.right.right = Node( 9 )
maxSubtreeElement = {}
dfsMaxSubtreeElement(root, maxSubtreeElement)
max_Elements = []
def print_max_elements(root, dp):
if root = = None :
return
print_max_elements(root.left, dp)
max_Elements.append(maxSubtreeElement[root.data])
print_max_elements(root.right, dp)
print_max_elements(root, maxSubtreeElement)
print (max_Elements)
|
C#
using System;
using System.Collections.Generic;
class Node {
public int data;
public Node left;
public Node right;
public Node( int x)
{
data = x;
left = null ;
right = null ;
}
}
class BinaryTree {
public int DfsMaxSubtreeElement(Node node,
int [] maxSubtreeElement)
{
if (node == null )
return 0;
int leftMax = DfsMaxSubtreeElement(
node.left, maxSubtreeElement);
int rightMax = DfsMaxSubtreeElement(
node.right, maxSubtreeElement);
int maxElement = Math.Max(
node.data, Math.Max(leftMax, rightMax));
maxSubtreeElement[node.data] = maxElement;
return maxElement;
}
static void Main( string [] args)
{
Node root = new Node(5);
root.left = new Node(3);
root.right = new Node(8);
root.left.left = new Node(2);
root.left.right = new Node(4);
root.right.left = new Node(7);
root.right.right = new Node(9);
int [] maxSubtreeElement = new int [10];
for ( int i = 0; i < maxSubtreeElement.Length; i++) {
maxSubtreeElement[i] = int .MinValue;
}
BinaryTree bt = new BinaryTree();
bt.DfsMaxSubtreeElement(root, maxSubtreeElement);
int k = 0;
while (maxSubtreeElement[k] == int .MinValue)
k++;
Console.Write( "[" + maxSubtreeElement[k]);
for ( int j = k + 1; j < maxSubtreeElement.Length;
j++) {
if (maxSubtreeElement[j] != int .MinValue)
Console.Write( ", " + maxSubtreeElement[j]);
}
Console.WriteLine( "]" );
}
}
|
Javascript
<script>
class Node {
constructor(data)
{
this .data = data;
this .left = null ;
this .right = null ;
}
}
function dfsMaxSubtreeElement(node, maxSubtreeElement)
{
if (!node) {
return 0;
}
let leftMax = dfsMaxSubtreeElement(node.left,
maxSubtreeElement);
let rightMax = dfsMaxSubtreeElement(node.right,
maxSubtreeElement);
let maxElement
= Math.max(node.data, Math.max(leftMax, rightMax));
maxSubtreeElement[node.data] = maxElement;
return maxElement;
}
const root = new Node(5);
root.left = new Node(3);
root.right = new Node(8);
root.left.left = new Node(2);
root.left.right = new Node(4);
root.right.left = new Node(7);
root.right.right = new Node(9);
const maxSubtreeElement
= Array(10).fill(Number.MIN_SAFE_INTEGER);
dfsMaxSubtreeElement(root, maxSubtreeElement);
let i = 0;
while (maxSubtreeElement[i] == Number.MIN_SAFE_INTEGER) {
i++;
}
let result = "[" + maxSubtreeElement[i];
for (let j = i + 1; j < maxSubtreeElement.length; j++) {
if (maxSubtreeElement[j] != Number.MIN_SAFE_INTEGER) {
result += ", " + maxSubtreeElement[j];
}
}
result += "]" ;
document.write(result);
</script>
|
Output
[2, 4, 4, 9, 7, 9, 9]
Time Complexity: O(N), where N is the number of nodes in the binary tree.
Auxiliary Space: O(N)
Complexity Analysis:
The time complexity of the DFS approach is O(n), where n is the number of nodes in the binary tree. This is because each node is processed once, and the time to process each node depends on the height of the tree, which is O(h), where h is the height of the tree. Since the height of a binary tree is O(log n) in the average case and O(n) in the worst case, the overall time complexity of the code is O(n).
The space complexity of the DFS approach is O(n), where n is the number of nodes in the binary tree. This is because the code uses a vector, maxSubtreeElement, to store the maximum element of every subtree of the binary tree. The size of the vector is equal to the number of nodes in the binary tree.
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...