从叶子节点开始烧掉一棵树的最短时间
给定一棵二叉树和这棵树的叶节点。众所周知,在 1 秒内,连接到给定节点(左孩子、右孩子和父母)的所有节点都会在 1 秒内被烧毁。然后通过一个中间连接的所有节点在 2 秒内被烧毁,以此类推。任务是找到燃烧完整二叉树所需的最短时间。
例子:
Input :
1
/ \
2 3
/ \ \
4 5 6
/ \ \
7 8 9
\
10
Leaf = 8
Output : 7
Initially 8 is set to fire at 0th sec.
1
/ \
2 3
/ \ \
4 5 6
/ \ \
7 F 9
\
10
After 1s: 5 is set to fire.
1
/ \
2 3
/ \ \
4 F 6
/ \ \
7 F 9
\
10
After 2s: 2, 7 are set to fire.
1
/ \
F 3
/ \ \
4 F 6
/ \ \
F F 9
\
10
After 3s: 4, 1 are set to fire.
F
/ \
F 3
/ \ \
F F 6
/ \ \
F F 9
\
10
After 4s: 3 is set to fire.
F
/ \
F F
/ \ \
F F 6
/ \ \
F F 9
\
10
After 5s: 6 is set to fire.
F
/ \
F F
/ \ \
F F F
/ \ \
F F 9
\
10
After 6s: 9 is set to fire.
F
/ \
F F
/ \ \
F F F
/ \ \
F F F
\
10
After 7s: 10 is set to fire.
F
/ \
F F
/ \ \
F F F
/ \ \
F F F
\
F
It takes 7s to burn the complete tree.
这个想法是为每个节点存储附加信息:
- 左子树的深度。
- 右子树的深度。
- 火灾从第一个燃烧的叶节点开始到达当前节点所需的时间。
- 一个布尔变量,用于检查初始烧毁节点是否在以当前节点为根的树中。
在继续使用该方法之前,让我们看一下下面的树:
1
/ \
2 3
/ \ /
4 5 6
/ / \
8 9 10
/
11
在上面的树中,如果我们将叶节点 11 设置为着火。
- 1s内,火势将到达节点9。
- 2s后,火将到达节点5。
- 在第 3 秒,火将到达节点 2 和 10。这里有一个观察结果:
- 在 2s 内火灾到达节点 5。对于节点 5,最初燃烧的叶子在它的左子树中,因此燃烧右子树所需的时间将是右子树的高度为 1。因此,火灾到达节点 10 在 ( 2+1) = 3 秒。
- 同样,对于节点 2。火在 3 秒内从右子树到达节点 2。因此,燃烧左子树所花费的时间将是它的高度。
所以解决方案是应用递归并为每个节点计算以下所需的值:
- 左深度。
- 正确的深度。
- 火灾到达当前节点所需的时间。
- 当前子树是否包含初始烧毁的叶子节点。
因此,燃烧任何子树所需的最短时间为:
The time required for fire to reach the root node from initial burnt leaf + depth of the opposite side
因此,要找到烧毁整棵树所需的时间,我们需要计算每个节点的上述值,并取该值的最大值。
ans = max(ans, (time required for fire to reach current node + depth of other subtree))
下面是上述方法的实现:
C++
// C++ program to find minimum time required
// to burn the binary tree completely
#include
using namespace std;
// Tree Node
struct Node {
int data;
Node* left;
Node* right;
Node()
{
left = NULL;
right = NULL;
}
};
// Utility function to create a new Node
Node* newNode(int val)
{
Node* temp = new Node;
temp->data = val;
return temp;
}
/*
***********ADDITIONAL INFO*************
lDepth - maximum height of left subtree
rDepth - maximum height of right subtree
contains - stores true if tree rooted at current
node contains the first burnt node time - time to reach
fire from the initially burnt leaf node to this node
*/
struct Info {
int lDepth;
int rDepth;
bool contains;
int time;
Info()
{
lDepth = rDepth = 0;
contains = false;
time = -1;
}
};
/*
Function to calculate time required to burn
tree completely
node - address of current node
info - extra information about current node
target - node that is fired
res - stores the result
*/
Info calcTime(Node* node, Info& info, int target, int& res)
{
// Base case: if root is null
if (node == NULL) {
return info;
}
// If current node is leaf
if (node->left == NULL && node->right == NULL) {
// If current node is the first burnt node
if (node->data == target) {
info.contains = true;
info.time = 0;
}
return info;
}
// Information about left child of root
Info leftInfo;
calcTime(node->left, leftInfo, target, res);
// Information about right child of root
Info rightInfo;
calcTime(node->right, rightInfo, target, res);
// If left subtree contains the fired node then
// time required to reach fire to current node
// will be (1 + time required for left child)
info.time = (node->left && leftInfo.contains)
? (leftInfo.time + 1)
: -1;
// If right subtree contains the fired node then
// time required to reach fire to current node
// will be (1 + time required for right child)
if (info.time == -1)
info.time = (node->right && rightInfo.contains)
? (rightInfo.time + 1)
: -1;
// Storing(true or false) if the tree rooted at
// current node contains the fired node
info.contains
= ((node->left && leftInfo.contains)
|| (node->right && rightInfo.contains));
// Calculate the maximum depth of left subtree
info.lDepth
= !(node->left)
? 0
: (1 + max(leftInfo.lDepth, leftInfo.rDepth));
// Calculate the maximum depth of right subtree
info.rDepth
= !(node->right)
? 0
: (1
+ max(rightInfo.lDepth, rightInfo.rDepth));
// Calculating answer
if (info.contains) {
// If left subtree exists and
// it contains the fired node
if (node->left && leftInfo.contains) {
// calculate result
res = max(res, info.time + info.rDepth);
}
// If right subtree exists and it
// contains the fired node
if (node->right && rightInfo.contains) {
// calculate result
res = max(res, info.time + info.lDepth);
}
}
}
// Driver function to calculate minimum
// time required
int minTime(Node* root, int target)
{
int res = 0;
Info info;
calcTime(root, info, target, res);
return res;
}
// Driver Code
int main()
{
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->left->left->left = newNode(8);
root->left->right->left = newNode(9);
root->left->right->right = newNode(10);
root->left->right->left->left = newNode(11);
// target node is 8
int target = 11;
cout << minTime(root, target);
return 0;
}
Java
// Java program to find minimum time required
// to burn the binary tree completely
public class GFG {
// Tree Node
static class Node {
int data;
Node left, right;
Node(int data)
{
this.data = data;
this.left = null;
this.right = null;
}
}
/*
***********ADDITIONAL INFO*************
lDepth - maximum height of left subtree
rDepth - maximum height of right subtree
contains - stores true if tree rooted at current node
contains the first burnt node
time - time to reach fire from the initially burnt leaf
node to this node
*/
static class Data {
int leftDepth, rightDepth, time;
boolean contains;
Data()
{
contains = false;
leftDepth = rightDepth = 0;
time = -1;
}
}
/*
Function to calculate time required to burn
tree completely
node - address of current node
info - extra information about current node
target - node that is fired
res - stores the result
*/
public static void getResult(Node node, Data data, int target)
{
// Base case: if root is null
if (node == null) {
return;
}
// If current node is leaf
if (node.left == null && node.right == null) {
// If current node is the first burnt node
if (node.data == target) {
data.contains = true;
data.time = 0;
}
return;
}
// Information about left child
Data leftData = new Data();
getResult(node.left, leftData, target);
// Information about right child
Data rightData = new Data();
getResult(node.right, rightData, target);
// If left subtree contains the fired node then
// time required to reach fire to current node
// will be (1 + time required for left child)
data.time = (leftData.contains) ? (leftData.time + 1) : -1;
// If right subtree contains the fired node then
// time required to reach fire to current node
// will be (1 + time required for right child)
if (data.time == -1)
data.time = (rightData.contains) ? (rightData.time + 1) : -1;
// Storing(true or false) if the tree rooted at
// current node contains the fired node
data.contains = (leftData.contains || rightData.contains);
// Calculate the maximum depth of left subtree
data.leftDepth = (node.left == null) ? 0 : (1 + Math.max(leftData.leftDepth, leftData.rightDepth));
// Calculate the maximum depth of right subtree
data.rightDepth = (node.right == null) ? 0 : (1 + Math.max(rightData.leftDepth, rightData.rightDepth));
// Calculating answer
if (data.contains) {
// If left subtree exists and
// it contains the fired node
if (leftData.contains) {
// calculate result
res = Math.max(res, data.time + data.rightDepth);
}
// If right subtree exists and it
// contains the fired node
if (rightData.contains) {
// calculate result
res = Math.max(res, data.time + data.leftDepth);
}
}
}
// To store the result
public static int res;
// Driver Code
public static void main(String args[])
{
Node root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.left.left.left = new Node(8);
root.left.right.left = new Node(9);
root.left.right.right = new Node(10);
root.left.right.left.left = new Node(11);
int target = 11;
res = 0;
getResult(root, new Data(), target);
System.out.println(res);
}
}
Python3
# Python program to find minimum time required
# to burn the binary tree completely
# Definition for a binary tree node
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
'''
***********ADDITIONAL INFO*************
lDepth - maximum height of left subtree
rDepth - maximum height of right subtree
contains - stores true if tree rooted at current node
contains the first burnt node
time - time to reach fire from the initially burnt leaf
node to this node
'''
class Info:
def __init__(self):
self.lDepth = 0
self.rDepth = 0
self.contains = False
self.time = -1
class Solution:
# Class Variable
res = 0
'''
Function to calculate time required to burn
tree completely
node - address of current node
info - extra information about current node
target - node that is fired
res - stores the result
'''
def calcTime(self, node, info, target):
# Base case: if root is null
if node == None:
return info
if node.left == None and node.right == None:
# If current node is the first burnt node
if node.val == target:
info.contains = True
info.time = 0
return info
# Information about left child of root
leftInfo = Info()
leftInfo = self.calcTime(node.left, leftInfo, target)
# Information about right child of root
rightInfo = Info()
rightInfo = self.calcTime(node.right, rightInfo, target)
# If left subtree contains the fired node then
# time required to reach fire to current node
# will be (1 + time required for left child)
info.time = leftInfo.time + \
1 if (node.left and leftInfo.contains) else -1
# If right subtree contains the fired node then
# time required to reach fire to current node
# will be (1 + time required for right child)
if info.time == -1:
info.time = rightInfo.time + \
1 if (node.right and rightInfo.contains) else -1
# Storing(true or false) if the tree rooted at
# current node contains the fired node
info.contains = (node.left and leftInfo.contains) or (
node.right and rightInfo.contains)
# Calculate the maximum depth of left subtree
info.lDepth = 0 if (not node.left) else (
1+max(leftInfo.lDepth, leftInfo.rDepth))
# Calculate the maximum depth of right subtree
info.rDepth = 0 if (not node.right) else (
1+max(rightInfo.lDepth, rightInfo.rDepth))
# Calculating answer
if info.contains:
# If left subtree exists and
# it contains the fired node
if node.left and leftInfo.contains:
# calculate result
self.res = max(self.res, info.time+info.rDepth)
# If right subtree exists and it
# contains the fired node
if node.right and rightInfo.contains:
# calculate result
self.res = max(self.res, info.time+info.lDepth)
return info
# Driver function to calculate minimum
# time required
def solve(self, root, target):
info = Info()
self.calcTime(root, info, target)
return self.res
# Driver Code
if __name__ == '__main__':
# Construct tree shown in the above example
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)
root.right.left = TreeNode(6)
root.left.left.left = TreeNode(8)
root.left.right.left = TreeNode(9)
root.left.right.right = TreeNode(10)
root.left.right.left.left = TreeNode(11)
# Target Leaf Node
target = 11
# Print min time to burn the complete tree
s = Solution()
print(s.solve(root, target))
# This code is contributed by Naman Taneja
C#
// C# program to find minimum time required
// to burn the binary tree completely
using System;
class GFG
{
// Tree Node
class Node
{
public int data;
public Node left, right;
public Node(int data)
{
this.data = data;
this.left = null;
this.right = null;
}
}
/*
***********ADDITIONAL INFO*************
lDepth - maximum height of left subtree
rDepth - maximum height of right subtree
contains - stores true if tree rooted at current node
contains the first burnt node
time - time to reach fire from the initially burnt leaf
node to this node
*/
class Data
{
public int leftDepth, rightDepth, time;
public bool contains;
public Data()
{
contains = false;
leftDepth = rightDepth = 0;
time = -1;
}
}
/*
Function to calculate time required to burn
tree completely
node - address of current node
info - extra information about current node
target - node that is fired
res - stores the result
*/
static void getResult(Node node, Data data,
int target)
{
// Base case: if root is null
if (node == null)
{
return;
}
// If current node is leaf
if (node.left == null &&
node.right == null)
{
// If current node is the first burnt node
if (node.data == target)
{
data.contains = true;
data.time = 0;
}
return;
}
// Information about left child
Data leftData = new Data();
getResult(node.left, leftData, target);
// Information about right child
Data rightData = new Data();
getResult(node.right, rightData, target);
// If left subtree contains the fired node then
// time required to reach fire to current node
// will be (1 + time required for left child)
data.time = (leftData.contains) ?
(leftData.time + 1) : -1;
// If right subtree contains the fired node then
// time required to reach fire to current node
// will be (1 + time required for right child)
if (data.time == -1)
data.time = (rightData.contains) ?
(rightData.time + 1) : -1;
// Storing(true or false) if the tree rooted at
// current node contains the fired node
data.contains = (leftData.contains ||
rightData.contains);
// Calculate the maximum depth of left subtree
data.leftDepth = (node.left == null) ?
0 : (1 + Math.Max(
leftData.leftDepth,
leftData.rightDepth));
// Calculate the maximum depth of right subtree
data.rightDepth = (node.right == null) ?
0 : (1 + Math.Max(
rightData.leftDepth,
rightData.rightDepth));
// Calculating answer
if (data.contains)
{
// If left subtree exists and
// it contains the fired node
if (leftData.contains)
{
// calculate result
res = Math.Max(res, data.time +
data.rightDepth);
}
// If right subtree exists and it
// contains the fired node
if (rightData.contains)
{
// calculate result
res = Math.Max(res, data.time +
data.leftDepth);
}
}
}
// To store the result
public static int res;
// Driver Code
public static void Main(String []args)
{
Node root = new Node(1);
root.left = new Node(2);
root.right = new Node(3);
root.left.left = new Node(4);
root.left.right = new Node(5);
root.right.left = new Node(6);
root.left.left.left = new Node(8);
root.left.right.left = new Node(9);
root.left.right.right = new Node(10);
root.left.right.left.left = new Node(11);
int target = 11;
res = 0;
getResult(root, new Data(), target);
Console.WriteLine(res);
}
}
// This code is contributed by PrinciRaj1992
输出:
6