Given the root of a binary tree and a target node, find the minimum time required to burn the entire tree if the target node is set on fire. In one second, the fire spreads from a node to its left child, right child, and parent. Note: The tree contains unique values.
[Approach- 1] Using Queue - O(n) Time and O(n) Space
The fire spreads to neighboring nodes first, then to their neighbors, and so on. In other words, the fire spreads level by level. To simulate this, we use BFS to traverse the tree in all directions, towards children and the parent. Since we need to move upwards, we first keep track of the parent of each node. Then, starting from the target node, we perform a level-order traversal. The number of levels traversed during this process gives the minimum time required to burn the entire tree.
In JavaScript there is no any built in queue so we are using custom queue.
C++
#include<iostream>#include<queue>#include<unordered_map>usingnamespacestd;// Node StructureclassNode{public:intdata;Node*left,*right;Node(intx){data=x;left=nullptr;right=nullptr;}};intminTime(Node*root,inttarget){if(root==nullptr)return-1;queue<Node*>q;q.push(root);Node*tar;// Map to keep track of parent of every nodeunordered_map<Node*,Node*>par;par[root]=nullptr;while(!q.empty()){Node*curr=q.front();q.pop();// Set the target nodeif(curr->data==target)tar=curr;// Push the left childif(curr->left!=nullptr){par[curr->left]=curr;q.push(curr->left);}// Push the right childif(curr->right!=nullptr){par[curr->right]=curr;q.push(curr->right);}}// map to keep track of visted or not visted nodeunordered_map<Node*,bool>vis;intans=-1;q.push(tar);while(!q.empty()){intsize=q.size();while(size--){Node*curr=q.front();vis[curr]=true;q.pop();// Push the left child node.if(curr->left!=nullptr&&!vis[curr->left])q.push(curr->left);// Push the right child node.if(curr->right!=nullptr&&!vis[curr->right])q.push(curr->right);// Push the parent node. if(par[curr]!=nullptr&&!vis[par[curr]])q.push(par[curr]);}ans++;}returnans;}intmain(){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);root->right->right=newNode(7);inttarget=2;cout<<minTime(root,target)<<endl;return0;}
Java
importjava.util.LinkedList;importjava.util.Queue;importjava.util.HashMap;importjava.util.Map;// Node StructureclassNode{intdata;Nodeleft,right;Node(intx){data=x;left=null;right=null;}}classGFG{staticintminTime(Noderoot,inttarget){if(root==null)return-1;Queue<Node>q=newLinkedList<>();q.add(root);Nodetar=null;// Map to keep track of parent of every nodeMap<Node,Node>par=newHashMap<>();par.put(root,null);while(!q.isEmpty()){Nodecurr=q.poll();// Set the target nodeif(curr.data==target)tar=curr;// Insert the left childif(curr.left!=null){par.put(curr.left,curr);q.add(curr.left);}// Insert the right childif(curr.right!=null){par.put(curr.right,curr);q.add(curr.right);}}// map to keep track of visited or not visited nodeMap<Node,Boolean>vis=newHashMap<>();intans=-1;q.add(tar);while(!q.isEmpty()){intsize=q.size();while(size-->0){Nodecurr=q.poll();vis.put(curr,true);// Push the left child node.if(curr.left!=null&&!vis.containsKey(curr.left))q.add(curr.left);// Push the right child node.if(curr.right!=null&&!vis.containsKey(curr.right))q.add(curr.right);// Push the parent node.if(par.get(curr)!=null&&!vis.containsKey(par.get(curr)))q.add(par.get(curr));}ans++;}returnans;}publicstaticvoidmain(String[]args){Noderoot=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);root.right.right=newNode(7);inttarget=2;System.out.println(minTime(root,target));}}
Python
fromcollectionsimportdeque# Node StructureclassNode:def__init__(self,x):self.data=xself.left=Noneself.right=NonedefminTime(root,target):ifrootisNone:return-1q=deque()q.append(root)tar=None# Map to keep track of parent of every nodepar={root:None}whileq:curr=q.popleft()# Set the target nodeifcurr.data==target:tar=curr# Insert the left childifcurr.left:par[curr.left]=currq.append(curr.left)# Insert the right childifcurr.right:par[curr.right]=currq.append(curr.right)# map to keep track of visited or not visited nodevis={}ans=-1q.append(tar)whileq:size=len(q)for_inrange(size):curr=q.popleft()vis[curr]=True# Push the left child node.ifcurr.leftandcurr.leftnotinvis:q.append(curr.left)# Push the right child node.ifcurr.rightandcurr.rightnotinvis:q.append(curr.right)# Push the parent node.ifpar[curr]andpar[curr]notinvis:q.append(par[curr])ans+=1returnansif__name__=="__main__":root=Node(1)root.left=Node(2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)root.right.left=Node(6)root.right.right=Node(7)target=2print(minTime(root,target))
C#
usingSystem;usingSystem.Collections.Generic;// Node StructureclassNode{publicintdata;publicNodeleft,right;publicNode(intx){data=x;left=null;right=null;}}classGFG{staticintminTime(Noderoot,inttarget){if(root==null)return-1;Queue<Node>q=newQueue<Node>();q.Enqueue(root);Nodetar=null;// Map to keep track of parent of every nodeDictionary<Node,Node>par=newDictionary<Node,Node>();par[root]=null;while(q.Count>0){Nodecurr=q.Dequeue();// Set the target nodeif(curr.data==target)tar=curr;// Insert the left childif(curr.left!=null){par[curr.left]=curr;q.Enqueue(curr.left);}// Insert the right childif(curr.right!=null){par[curr.right]=curr;q.Enqueue(curr.right);}}// map to keep track of visited or not visited nodeDictionary<Node,bool>vis=newDictionary<Node,bool>();intans=-1;q.Enqueue(tar);while(q.Count>0){intsize=q.Count;for(inti=0;i<size;i++){Nodecurr=q.Dequeue();vis[curr]=true;// Push the left child node.if(curr.left!=null&&!vis.ContainsKey(curr.left))q.Enqueue(curr.left);// Push the right child node.if(curr.right!=null&&!vis.ContainsKey(curr.right))q.Enqueue(curr.right);// Push the parent node.if(par[curr]!=null&&!vis.ContainsKey(par[curr]))q.Enqueue(par[curr]);}ans++;}returnans;}staticvoidMain(string[]args){Noderoot=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);root.right.right=newNode(7);inttarget=2;Console.WriteLine(minTime(root,target));}}
JavaScript
// Queue nodeclassQNode{constructor(data){this.data=data;this.next=null;}}// Custom Queue implementationclassQueue{constructor(){this.front=null;this.rear=null;this._length=0;}// Check if queue is emptyisEmpty(){returnthis._length===0;}// Return current queue sizesize(){returnthis._length;}// Enqueue a nodeenqueue(x){if(!x)return;// ignore nullletnewNode=newQNode(x);if(this.rear===null){this.front=this.rear=newNode;}else{this.rear.next=newNode;this.rear=newNode;}this._length++;}// Dequeue a nodedequeue(){if(this.front===null)returnnull;lettemp=this.front;this.front=this.front.next;if(this.front===null)this.rear=null;this._length--;returntemp.data;}}// Node StructureclassNode{constructor(x){this.data=x;this.left=null;this.right=null;}}// Function to calculate minimum time// to burn the tree from targetfunctionminTime(root,target){if(root===null)return-1;// Map child -> parentconstpar=newMap();constq1=newQueue();q1.enqueue(root);par.set(root,null);// target node referencelettar=null;// BFS to map parents and find target nodewhile(!q1.isEmpty()){constcurr=q1.dequeue();// Set target node referenceif(curr.data===target)tar=curr;// Map left child to parent and enqueueif(curr.left!==null){par.set(curr.left,curr);q1.enqueue(curr.left);}// Map right child to parent and enqueueif(curr.right!==null){par.set(curr.right,curr);q1.enqueue(curr.right);}}// If target node not found, return 0if(!tar)return0;// Queue for BFS to simulate burning treeconstq2=newQueue();// track visited nodesconstvis=newMap();q2.enqueue(tar);vis.set(tar,true);letans=0;// BFS level by levelwhile(!q2.isEmpty()){letlevelSize=q2.size();letprocessed=0;while(processed<levelSize){constcurr=q2.dequeue();// Enqueue left child if not visitedif(curr.left&&!vis.has(curr.left)){q2.enqueue(curr.left);vis.set(curr.left,true);}// Enqueue right child if not visitedif(curr.right&&!vis.has(curr.right)){q2.enqueue(curr.right);vis.set(curr.right,true);}// Enqueue parent if not visitedconstparent=par.get(curr);if(parent&&!vis.has(parent)){q2.enqueue(parent);vis.set(parent,true);}processed++;}// Increment time after burning one levelif(!q2.isEmpty())ans++;}returnans;}// Driver code// Construct binary tree// 1// / \// 2 3// / \ / \// 4 5 6 7letroot=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);root.right.right=newNode(7);lettarget=2;console.log(minTime(root,target));
Output
3
[Alternate Approach] Using Recursion - O(n) Time and O(h) Space
The fire spreads level by level from the target node. The total time to burn the entire tree is determined by the farthest node reached by the fire. In other words, the minimum time to burn the whole tree is simply the distance from the target node to the farthest node. This reduces the problem to finding the farthest node from the target.
The idea is to find the parent of each node and recursively explore all paths from the target node to find the farthest node. The distance to this node gives the minimum time required to burn the entire tree.
C++
#include<iostream>#include<unordered_map>#include<algorithm>usingnamespacestd;classNode{public:intdata;Node*left;Node*right;Node(intx){data=x;left=nullptr;right=nullptr;}};// Recursively set parent for each nodevoidsetParent(Node*root,unordered_map<int,Node*>&parent){if(!root)return;if(root->left){parent[root->left->data]=root;setParent(root->left,parent);}if(root->right){parent[root->right->data]=root;setParent(root->right,parent);}}// Recursively find target nodeNode*findTarget(Node*root,inttarget){if(!root)returnnullptr;if(root->data==target)returnroot;Node*left=findTarget(root->left,target);if(left)returnleft;returnfindTarget(root->right,target);}// DFS to calculate minimum time to burn entire treeintdfs(Node*node,unordered_map<int,int>&visited,unordered_map<int,Node*>&parent){if(!node||visited[node->data])return0;visited[node->data]=1;// dfs call for left and right childinttimeLeft=dfs(node->left,visited,parent);inttimeRight=dfs(node->right,visited,parent);inttimeParent=0;// call dfs for parent if parnet is not visitedif(parent.find(node->data)!=parent.end())timeParent=dfs(parent[node->data],visited,parent);returnmax({timeLeft,timeRight,timeParent})+1;}intminTime(Node*root,inttarget){unordered_map<int,Node*>parent;setParent(root,parent);Node*targetNode=findTarget(root,target);unordered_map<int,int>visited;returndfs(targetNode,visited,parent)-1;}intmain(){// 1// / \ // 2 3// / \ / \ // 4 5 6 7Node*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);root->right->right=newNode(7);inttarget=2;cout<<minTime(root,target)<<endl;return0;}
Java
importjava.util.HashMap;importjava.util.Map;classNode{intdata;Nodeleft,right;Node(intx){data=x;left=null;right=null;}}publicclassBurnTree{// Recursively set the parent of every nodestaticvoidsetParent(Noderoot,Map<Integer,Node>parent){if(root==null)return;if(root.left!=null){parent.put(root.left.data,root);setParent(root.left,parent);}if(root.right!=null){parent.put(root.right.data,root);setParent(root.right,parent);}}// Recursively find the target nodestaticNodefindTarget(Noderoot,inttarget){if(root==null)returnnull;if(root.data==target)returnroot;Nodeleft=findTarget(root.left,target);if(left!=null)returnleft;returnfindTarget(root.right,target);}// DFS to find minimum time to burn tree from targetstaticintdfs(Nodenode,Map<Integer,Boolean>visited,Map<Integer,Node>parent){if(node==null||visited.getOrDefault(node.data,false))return0;visited.put(node.data,true);// dfs call for left and right childintleft=dfs(node.left,visited,parent);intright=dfs(node.right,visited,parent);// dfs call for parent if parent is not visitedintparTime=parent.containsKey(node.data)?dfs(parent.get(node.data),visited,parent):0;returnMath.max(Math.max(left,right),parTime)+1;}staticintminTime(Noderoot,inttarget){Map<Integer,Node>parent=newHashMap<>();setParent(root,parent);NodetargetNode=findTarget(root,target);Map<Integer,Boolean>visited=newHashMap<>();returndfs(targetNode,visited,parent)-1;}publicstaticvoidmain(String[]args){// 1// / \// 2 3// / \ / \// 4 5 6 7Noderoot=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);root.right.right=newNode(7);inttarget=2;System.out.println(minTime(root,target));}}
Python
classNode:def__init__(self,x):self.data=xself.left=Noneself.right=None# Recursively set the parent of every nodedefsetParent(root,parent):ifnotroot:returnifroot.left:parent[root.left.data]=rootsetParent(root.left,parent)ifroot.right:parent[root.right.data]=rootsetParent(root.right,parent)# Recursively find the target nodedeffindTarget(root,target):ifnotroot:returnNoneifroot.data==target:returnrootleft=findTarget(root.left,target)ifleft:returnleftreturnfindTarget(root.right,target)# DFS to find minimum time to burn tree from targetdefdfs(node,visited,parent):ifnotnodeorvisited.get(node.data,False):return0visited[node.data]=True# dfs call for left and right childleft=dfs(node.left,visited,parent)right=dfs(node.right,visited,parent)# dfs call for parent if parent is not visitedpar_time=dfs(parent[node.data],visited,parent)ifnode.datainparentelse0returnmax(left,right,par_time)+1defminTime(root,target):parent={}setParent(root,parent)targetNode=findTarget(root,target)visited={}returndfs(targetNode,visited,parent)-1if__name__=="__main__":# 1# / \# 2 3# / \ / \# 4 5 6 7root=Node(1)root.left=Node(2)root.right=Node(3)root.left.left=Node(4)root.left.right=Node(5)root.right.left=Node(6)root.right.right=Node(7)print(minTime(root,2))
C#
usingSystem;usingSystem.Collections.Generic;classNode{publicintdata;publicNodeleft,right;publicNode(intx){data=x;left=null;right=null;}}classGFG{// Recursively set the parent of every nodestaticvoidsetParent(Noderoot,Dictionary<int,Node>parent){if(root==null)return;if(root.left!=null){parent[root.left.data]=root;setParent(root.left,parent);}if(root.right!=null){parent[root.right.data]=root;setParent(root.right,parent);}}// Recursively find the target nodestaticNodefindTarget(Noderoot,inttarget){if(root==null)returnnull;if(root.data==target)returnroot;Nodeleft=findTarget(root.left,target);if(left!=null)returnleft;returnfindTarget(root.right,target);}// DFS to find minimum time to burn tree from targetstaticintdfs(Nodenode,Dictionary<int,bool>visited,Dictionary<int,Node>parent){if(node==null||visited.ContainsKey(node.data)&&visited[node.data])return0;visited[node.data]=true;intleft=dfs(node.left,visited,parent);intright=dfs(node.right,visited,parent);intparTime=parent.ContainsKey(node.data)?dfs(parent[node.data],visited,parent):0;returnMath.Max(Math.Max(left,right),parTime)+1;}staticintminTime(Noderoot,inttarget){varparent=newDictionary<int,Node>();setParent(root,parent);NodetargetNode=findTarget(root,target);varvisited=newDictionary<int,bool>();returndfs(targetNode,visited,parent)-1;}staticvoidMain(){// 1// / \// 2 3// / \ / \// 4 5 6 7Noderoot=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);root.right.right=newNode(7);Console.WriteLine(minTime(root,2));}}
JavaScript
classNode{constructor(data){this.data=data;this.left=null;this.right=null;}}// Recursively set the parent of every nodefunctionsetParent(root,parent){if(!root)return;if(root.left){parent[root.left.data]=root;setParent(root.left,parent);}if(root.right){parent[root.right.data]=root;setParent(root.right,parent);}}// Recursively find the target nodefunctionfindTarget(root,target){if(!root)returnnull;if(root.data===target)returnroot;letleft=findTarget(root.left,target);if(left)returnleft;returnfindTarget(root.right,target);}// DFS to find minimum time to burn tree from targetfunctiondfs(node,visited,parent){if(!node||visited[node.data])return0;visited[node.data]=true;letleft=dfs(node.left,visited,parent);letright=dfs(node.right,visited,parent);letparTime=parent[node.data]?dfs(parent[node.data],visited,parent):0;returnMath.max(left,right,parTime)+1;}functionminTime(root,target){constparent={};setParent(root,parent);consttargetNode=findTarget(root,target);constvisited={};returndfs(targetNode,visited,parent)-1;}// Driver Code// 1// / \// 2 3// / \ / \// 4 5 6 7letroot=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);root.right.right=newNode(7);console.log(minTime(root,2));