Monday, November 25, 2024
Google search engine
HomeData Modelling & AIMinimum time required to infect all the nodes of Binary tree

Minimum time required to infect all the nodes of Binary tree

Given a binary tree and a node start that is initially infected. For every second, neighbours of an infected node get infected. The task is to find the minimum time in which the whole tree will be infected.

Examples:

Input:
         10
      /     \
 12      13
        /       \
    14        15
   /  \        /   \
21 22  23  24
Start = 14
Output: 3

Input: 
       3
    /    \
  4      1
            \
             2
Start = 1
Output: 2

An approach using BFS (Breadth-first search):

The idea to solve this problem is by doing the BFS (breadth-first search) algorithm on the tree,  

Starts from the given special node “start”. During the BFS make all adjacent node infected. Keep counting the time in result, where we have visited all the node. 

One problem while infecting the adjacent node is that we can easily know the node’s children (left child or right child) which is adjacent but we can’t know that node’s parent directly. So, to overcome this problem we have to generate a parent-node relationship into some data structure, there we can keep track to node’s parent.

Follow the steps below to implement the above idea:

  • Store parent-child relations for each node in the parent array. (i.e, keeping track of the parent of any node)
  • Find the actual node “node” of a given special node start in the tree.
  • Create a queue for performing the BFS and an array visited to keep track of which node has already been infected.
  • Do BFS (Breadth-first search) by initially storing the “node” in the queue and making this “node” visited.
  • Do the following while queue size is greater than zero.
    • Iterate over the size of the queue and do the following:
      • Check if the current node’s parent exists in the tree and is not infected yet.
        • Push into the queue and make it visited to show it’s infected now.
      • Check if the current node’s left child exists in the tree and is not infected yet.
        • Push into the queue and make it visited to show it’s infected now.
      • Check if the current node’s right exists in the tree and is not infected yet.
        • Push into the queue and make it visited to show it’s infected now.
    • Increment the result by 1. (i.e, the infection has already spread by the above steps for this time.)
  • Return the result.

Below is the implementation of the above approach.

C++




// C++ code for the above approach:
 
#include <bits/stdc++.h>
using namespace std;
 
// A Tree node
struct Node {
    int val;
    struct Node *left, *right;
};
 
// Utility function to create a new node
Node* newNode(int val)
{
    Node* temp = new Node;
    temp->val = val;
    temp->left = temp->right = NULL;
    return (temp);
}
 
// "node" will store the actual Tree node
// of special node "start".
Node* node = NULL;
 
// Function for generating
// parent-root relationship
void findParent(Node* root, Node* p, vector<Node*>& parent,
                int start)
{
    if (root == NULL)
        return;
 
    // Store parent of current node
    parent[root->val] = p;
    if (root->val == start) {
        node = root;
    }
 
    findParent(root->left, root, parent, start);
    findParent(root->right, root, parent, start);
}
 
// Function to return the minimum amount
// of time require to infect all the
// nodes of binary tree
int amountOfTime(Node* root, int start)
{
 
    vector<Node*> parent(100005, NULL);
    findParent(root, NULL, parent, start);
 
    vector<bool> visited(100005, false);
 
    queue<Node*> q;
 
    // Push special tree node into the
    // queue and make it visited.
    q.push(node);
    visited[start] = true;
 
    // This store the minimum time require
    // to infect all the tree node.
    int result = -1;
 
    while (q.size() > 0) {
        int n = q.size();
 
        for (int i = 0; i < n; i++) {
            auto curr = q.front();
            int currNode = curr->val;
            q.pop();
 
            // Check if parent of currNode
            // exist and not visited yet
            // then push this parent of
            // current node into queue.
            if (parent[currNode] != NULL
                && visited[parent[currNode]->val]
                       == false) {
                visited[parent[currNode]->val] = true;
                q.push(parent[currNode]);
            }
 
            // Check if current node left
            // child exist and not
            // visited yet.
            if (curr->left
                && visited[curr->left->val] == false) {
                visited[curr->left->val] = true;
                q.push(curr->left);
            }
 
            // Check if current node right
            // child exist and not
            // visited yet.
            if (curr->right
                && visited[curr->right->val] == false) {
                visited[curr->right->val] = true;
                q.push(curr->right);
            }
        }
 
        // Increment the time
        result++;
    }
 
    // Return the result.
    return result;
}
 
// Driver Code
int main()
{
    /*      10
           /  \
          12  13
              / \
             14 15
            / \ / \
          21 22 23 24
 
        Let us create Binary Tree as shown
        above */
 
    Node* root = newNode(10);
    root->left = newNode(12);
    root->right = newNode(13);
 
    root->right->left = newNode(14);
    root->right->right = newNode(15);
 
    root->right->left->left = newNode(21);
    root->right->left->right = newNode(22);
    root->right->right->left = newNode(23);
    root->right->right->right = newNode(24);
 
    int start = 14;
 
    // Function call
    int result = amountOfTime(root, start);
    cout << result << endl;
 
    return 0;
}


Java




// Java code for the above approach
import java.io.*;
import java.util.*;
 
class Node {
  int val;
  Node left, right;
 
  public Node(int item)
  {
    val = item;
    left = right = null;
  }
}
 
class GFG {
  static Node node = null;
 
  // Function for generating
  // parent-root relationship
  static void findParent(Node root, Node p, Node[] parent,
                         int start)
  {
    if (root == null)
      return;
 
    // Store parent of current node
    parent[root.val] = p;
 
    if (root.val == start) {
      node = root;
    }
 
    findParent(root.left, root, parent, start);
    findParent(root.right, root, parent, start);
  }
 
  // Function to return the minimum amount
  // of time require to infect all the
  // nodes of binary tree
  static int amountOfTime(Node root, int start)
  {
 
    Node[] parent = new Node[100005];
    findParent(root, null, parent, start);
 
    boolean[] visited = new boolean[100005];
    Arrays.fill(visited, false);
 
    Queue<Node> q = new LinkedList<>();
 
    // add special tree node into the
    // queue and make it visited.
    q.add(node);
    visited[start] = true;
 
    // This store the minimum time require
    // to infect all the tree node.
    int result = -1;
 
    while (q.size() > 0) {
      int n = q.size();
 
      for (int i = 0; i < n; i++) {
        Node curr = q.peek();
        int currNode = curr.val;
        q.remove();
 
        // Check if parent of currNode
        // exist and not visited yet
        // then add this parent of
        // current node into queue.
        if (parent[currNode] != null
            && visited[parent[currNode].val]
            == false) {
          visited[parent[currNode].val] = true;
          q.add(parent[currNode]);
        }
 
        // Check if current node left
        // child exist and not
        // visited yet.
        if (curr.left!=null
            && visited[curr.left.val] == false) {
          visited[curr.left.val] = true;
          q.add(curr.left);
        }
 
        // Check if current node right
        // child exist and not
        // visited yet.
        if (curr.right!=null
            && visited[curr.right.val] == false) {
          visited[curr.right.val] = true;
          q.add(curr.right);
        }
      }
 
      // Increment the time
      result++;
    }
 
    // Return the result.
    return result;
  }
 
  public static void main(String[] args)
  {
    /*      10
           /  \
          12  13
              / \
             14 15
            / \ / \
          21 22 23 24
 
        Let us create Binary Tree as shown
        above */
 
    Node root = new Node(10);
    root.left = new Node(12);
    root.right = new Node(13);
 
    root.right.left = new Node(14);
    root.right.right = new Node(15);
 
    root.right.left.left = new Node(21);
    root.right.left.right = new Node(22);
    root.right.right.left = new Node(23);
    root.right.right.right = new Node(24);
 
    int start = 14;
 
    // Function call
    int result = amountOfTime(root, start);
    System.out.println(result);
  }
}
 
// This code is contributed by ishankhandelwals.


Python3




# Python program for the above approach
# A Tree node
class Node:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
 
# Utility function to create a new node
def newNode(val):
    return Node(val)
 
 
# "node" will store the actual Tree node
# of special node "start".
node = None
 
# Function for generating
# parent-root relationship
 
 
def findParent(root, p, parent, start):
    if not root:
        return
    # Store parent of current node
    parent[root.val] = p
    if root.val == start:
        global node
        node = root
    findParent(root.left, root, parent, start)
    findParent(root.right, root, parent, start)
 
# Function to return the minimum amount
# of time require to infect all the
# nodes of binary tree
 
 
def amountOfTime(root, start):
    parent = [None] * 100005
    findParent(root, None, parent, start)
 
    visited = [False] * 100005
 
    q = []
 
    # Push special tree node into the
    # queue and make it visited.
    q.append(node)
    visited[start] = True
 
    # This store the minimum time require
    # to infect all the tree node.
    result = -1
 
    while len(q) > 0:
        n = len(q)
        for i in range(n):
            curr = q.pop(0)
            currNode = curr.val
 
            # Check if parent of currNode
            # exist and not visited yet
            # then push this parent of
            # current node into queue.
            if parent[currNode] and not visited[parent[currNode].val]:
                visited[parent[currNode].val] = True
                q.append(parent[currNode])
 
            # Check if current node left
            # child exist and not
            # visited yet.
            if curr.left and not visited[curr.left.val]:
                visited[curr.left.val] = True
                q.append(curr.left)
 
            # Check if current node right
            # child exist and not
            # visited yet.
            if curr.right and not visited[curr.right.val]:
                visited[curr.right.val] = True
                q.append(curr.right)
 
        # Increment the time
        result += 1
 
    # Return the result.
    return result
 
 
# Driver Code
 
    """
      10
     /  \
    12  13
        / \
       14 15
      / \ / \
    21 22 23 24
 
    Let us create Binary Tree as shown
    above
    """
 
 
root = newNode(10)
root.left = newNode(12)
root.right = newNode(13)
 
root.right.left = newNode(14)
root.right.right = newNode(15)
 
root.right.left.left = newNode(21)
root.right.left.right = newNode(22)
root.right.right.left = newNode(23)
root.right.right.right = newNode(24)
 
start = 14
 
# Function call
result = amountOfTime(root, start)
print(result)
 
# This code is contributed by Potta Lokesh


C#




// C# code for the above approach:
using System;
using System.Collections.Generic;
 
public class Node {
  public int val;
  public Node left, right;
 
  public Node(int item)
  {
    val = item;
    left = right = null;
  }
}
 
public class GFG {
  // "node" will store the actual Tree node
  // of special node "start".
  public Node node;
 
  // Function for generating
  // parent-root relationship
  public void findParent(Node root, Node p, int[] parent,
                         int start)
  {
    if (root == null)
      return;
 
    // Store parent of current node
    parent[root.val] = p.val;
    if (root.val == start) {
      node = root;
    }
 
    findParent(root.left, root, parent, start);
    findParent(root.right, root, parent, start);
  }
 
  // Function to return the minimum amount
  // of time require to infect all the
  // nodes of binary tree
  public int amountOfTime(Node root, int start)
  {
    int[] parent = new int[100005];
    findParent(root, new Node(0), parent, start);
 
    bool[] visited = new bool[100005];
 
    Queue<Node> q = new Queue<Node>();
 
    // Push special tree node into the
    // queue and make it visited.
    q.Enqueue(node);
    visited[start] = true;
 
    // This store the minimum time require
    // to infect all the tree node.
    int result = -1;
 
    while (q.Count > 0) {
      int n = q.Count;
      for (int i = 0; i < n; i++) {
        var curr = q.Peek();
        int currNode = curr.val;
        q.Dequeue();
 
        // Check if parent of currNode
        // exist and not visited yet
        // then push this parent of
        // current node into queue.
        if (parent[currNode] != 0
            && visited[parent[currNode]] == false) {
          visited[parent[currNode]] = true;
          q.Enqueue(new Node(parent[currNode]));
        }
 
        // Check if current node left
        // child exist and not
        // visited yet.
        if (curr.left != null
            && visited[curr.left.val] == false) {
          visited[curr.left.val] = true;
          q.Enqueue(curr.left);
        }
 
        // Check if current node right
        // child exist and not
        // visited yet.
        if (curr.right != null
            && visited[curr.right.val] == false) {
          visited[curr.right.val] = true;
          q.Enqueue(curr.right);
        }
      }
      // Increment the time
      result++;
    }
 
    // Return the result.
    return result;
  }
 
  // Driver Code
  public static void Main(String[] args)
  {
    /*      10
               /  \
              12  13
                  / \
                 14 15
                / \ / \
              21 22 23 24
 
            Let us create Binary Tree as shown
            above */
 
    Node root = new Node(10);
    root.left = new Node(12);
    root.right = new Node(13);
 
    root.right.left = new Node(14);
    root.right.right = new Node(15);
 
    root.right.left.left = new Node(21);
    root.right.left.right = new Node(22);
    root.right.right.left = new Node(23);
    root.right.right.right = new Node(24);
 
    int start = 14;
 
    // Function call
    int result
      = new GFG().amountOfTime(root, start);
    Console.WriteLine(result);
  }
}
 
// This code is contributed by ishankhandelwals.


Javascript




// JS code
class Node
{
    constructor(item)
    {
        this.item = item;
        this.left = this.right = null;
    }
}
var node=null;
var item=null;
function findParent(root, p, parent,start)
{
if (root == null)
    return;
 
// Store parent of current node
parent[root.item] = p;
if (root.item == start) {
node = root;
}
 
findParent(root.left, root, parent, start);
findParent(root.right, root, parent, start);
}
 
 
function amountOfTime(root,start)
{
    let parent = new Array(100005);
    parent.fill(null);
 
    findParent(root, null, parent, start);
 
    let visited=new Array(100005);
    visited.fill(false);
 
    let q=[];
 
    // Push special tree node into the
    // queue and make it visited.
    q.push(node);
    visited[start] = true;
 
    // This store the minimum time require
    // to infect all the tree node.
    let result = -1;
 
    while (q.length > 0) {
        let n = q.length;
 
        for (let i = 0; i < n; i++) {
            let curr = q[0];
            let currNode = curr.item;
            q.shift();
 
            // Check if parent of currNode
            // exist and not visited yet
            // then push this parent of
            // current node into queue.
            if (parent[currNode] != null
                && visited[parent[currNode].item]
                       == false) {
                visited[parent[currNode].item] = true;
                q.push(parent[currNode]);
            }
 
            // Check if current node left
            // child exist and not
            // visited yet.
            if (curr.left
                && visited[curr.left.item] == false) {
                visited[curr.left.item] = true;
                q.push(curr.left);
            }
 
            // Check if current node right
            // child exist and not
            // visited yet.
            if (curr.right
                && visited[curr.right.item] == false) {
                visited[curr.right.item] = true;
                q.push(curr.right);
            }
        }
 
        // Increment the time
        result++;
    }
 
    // Return the result.
    return result;
}
 
 
// Driver Code
    /*      10
           /  \
          12  13
              / \
             14 15
            / \ / \
          21 22 23 24
 
        Let us create Binary Tree as shown
        above */
 
    let root = new Node(10);
    root.left = new Node(12);
    root.right = new Node(13);
 
    root.right.left = new Node(14);
    root.right.right = new Node(15);
 
    root.right.left.left = new Node(21);
    root.right.left.right = new Node(22);
    root.right.right.left = new Node(23);
    root.right.right.right = new Node(24);
 
    let start = 14;
 
    // Function call
    let result = amountOfTime(root, start);
    console.log(result);
     
    // This code is contributed by ishankhandlwals.


Output

3




Time Complexity: O(N), where N is the number of nodes in the binary tree.
Auxiliary Space: O(N)

Another method (Using Depth-first search (DFS))

The idea to solve this problem is by doing the  Depth-first search (DFS)  algorithm on the tree,

Algorithm

  • Create a function called “findParent” that takes a root node, a parent node pointer, a vector of Node pointers called “parent”, and an integer called “start”.
    • If the root node is NULL, return.
    • Store the parent of the current node in the “parent” vector at the index of the current node’s value.
    • If the current node’s value equals “start”, set the global “node” variable to the current node.
    • Recursively call the “findParent” function with the left and right children of the current node, passing in the current node as the parent node pointer.
  • Create a function called “amountOfTime” that takes a root node and an integer called “start”.
    • Create a “parent” vector of Node pointers with size 100005 and initialize all elements to NULL.
    • Call the “findParent” function with the root node, NULL as the parent node pointer, the “parent” vector, and the “start” integer.
    • Create a “visited” vector of bools with size 100005 and initialize all elements to false.
    • Declare an integer variable called “result” and initialize it to 0.
  • Define a lambda function called “dfs” that takes a Node pointer called “curr” and an integer called “dist”.
    • Mark the current node as visited in the “visited” vector.
    • Update the “result” variable to be the maximum of “result” and “dist”.
    • Traverse the current node’s left child, right child, and parent (if it exists) using a range-based for loop.
    • If a child or parent node is found and has not been visited before, recursively call the “dfs” function with the child/parent node and the updated distance.
    • Call the “dfs” function with the global “node” variable and 0 as the distance.
    • Return the “result” variable.

C++




#include <bits/stdc++.h>
using namespace std;
 
// A Tree node
struct Node {
    int val;
    struct Node *left, *right;
};
 
// Utility function to create a new node
Node* newNode(int val)
{
    Node* temp = new Node;
    temp->val = val;
    temp->left = temp->right = NULL;
    return (temp);
}
 
// "node" will store the actual Tree node
// of special node "start".
Node* node = NULL;
 
// Function for generating
// parent-root relationship
void findParent(Node* root, Node* p, vector<Node*>& parent,
                int start)
{
    if (root == NULL)
        return;
 
    // Store parent of current node
    parent[root->val] = p;
    if (root->val == start) {
        node = root;
    }
 
    findParent(root->left, root, parent, start);
    findParent(root->right, root, parent, start);
}
 
// Function to return the minimum amount
// of time require to infect all the
// nodes of binary tree
 int amountOfTime(Node* root, int start)
{
    vector<Node*> parent(100005, NULL);
    findParent(root, NULL, parent, start);
 
    vector<bool> visited(100005, false);
 
    int result = 0;
 
    function<void(Node*, int)> dfs = [&](Node* curr, int dist) {
        visited[curr->val] = true;
        result = max(result, dist);
        for (auto child : {curr->left, curr->right, parent[curr->val]}) {
            if (child && !visited[child->val]) {
                dfs(child, dist + 1);
            }
        }
    };
 
    dfs(node, 0);
 
    return result;
}
 
 
// Driver Code
int main()
{
    /*      10
           /  \
          12  13
              / \
             14 15
            / \ / \
          21 22 23 24
 
        Let us create Binary Tree as shown
        above */
 
    Node* root = newNode(10);
    root->left = newNode(12);
    root->right = newNode(13);
 
    root->right->left = newNode(14);
    root->right->right = newNode(15);
 
    root->right->left->left = newNode(21);
    root->right->left->right = newNode(22);
    root->right->right->left = newNode(23);
    root->right->right->right = newNode(24);
 
    int start = 14;
 
    // Function call
    int result = amountOfTime(root, start);
    cout << result << endl;
 
    return 0;
}


Python3




# A Tree node
class Node:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
 
#  Utility function to create a new node
def newNode(val):
    temp = Node(val)
    #temp.val =
    temp.left = None
    temp.right = None
    return temp
 
# "node" will store the actual Tree node
# of special node "start".
node = None
 
# Function for generating
# parent-root relationship
def findParent(root, p, parent, start):
    if root is None:
        return
    # Store parent of current node
    parent[root.val] = p
    if root.val == start:
        global node
        node = root
    findParent(root.left, root, parent, start)
    findParent(root.right, root, parent, start)
# Function to return the minimum amount
# of time require to infect all the
# nodes of binary tree
def amountOfTime(root, start):
    parent = [None] * 100005
    findParent(root, None, parent, start)
    visited = [False] * 100005
    result = 0
    def dfs(curr, dist):
        nonlocal result
        visited[curr.val] = True
        result = max(result, dist)
        for child in [curr.left, curr.right, parent[curr.val]]:
            if child and not visited[child.val]:
                dfs(child, dist + 1)
    dfs(node, 0)
    return result
 
# Driver Code
root = newNode(10)
root.left = newNode(12)
root.right = newNode(13)
root.right.left = newNode(14)
root.right.right = newNode(15)
root.right.left.left = newNode(21)
root.right.left.right = newNode(22)
root.right.right.left = newNode(23)
root.right.right.right = newNode(24)
start = 14
 
result = amountOfTime(root, start)
print(result)


C#




using System;
using System.Collections.Generic;
 
// A Tree node
public class Node
{
    public int val;
    public Node left, right;
 
    // Utility function to create a new node
    public Node(int val)
    {
        this.val = val;
        this.left = this.right = null;
    }
}
 
public class MinTimeToInfect
{
    // "node" will store the actual Tree node
    // of the special node "start".
    static Node node = null;
 
    // Function for generating
    // parent-root relationship
    static void FindParent(Node root, Node p, List<Node> parent, int start)
    {
        if (root == null)
            return;
 
        // Store parent of current node
        parent[root.val] = p;
        if (root.val == start)
        {
            node = root;
        }
 
        FindParent(root.left, root, parent, start);
        FindParent(root.right, root, parent, start);
    }
 
    // Function to return the minimum amount
    // of time required to infect all the
    // nodes of the binary tree
    static int AmountOfTime(Node root, int start)
    {
        List<Node> parent = new List<Node>(100005);
        for (int i = 0; i < 100005; i++)
        {
            parent.Add(null);
        }
 
        FindParent(root, null, parent, start);
 
        bool[] visited = new bool[100005];
        int[] result = new int[] { 0 };
 
        // DFS function
        // It is declared here to access the `result` variable
        Action<Node, int> dfs = null;
        dfs = (curr, dist) =>
        {
            visited[curr.val] = true;
            result[0] = Math.Max(result[0], dist);
            foreach (var child in new Node[] { curr.left, curr.right, parent[curr.val] })
            {
                if (child != null && !visited[child.val])
                {
                    dfs(child, dist + 1);
                }
            }
        };
 
        dfs(node, 0);
 
        return result[0];
    }
 
    // Driver Code
    public static void Main(string[] args)
    {
        /*      10
               /  \
              12  13
                  / \
                 14 15
                / \ / \
              21 22 23 24
 
            Let us create Binary Tree as shown
            above */
 
        Node root = new Node(10);
        root.left = new Node(12);
        root.right = new Node(13);
 
        root.right.left = new Node(14);
        root.right.right = new Node(15);
 
        root.right.left.left = new Node(21);
        root.right.left.right = new Node(22);
        root.right.right.left = new Node(23);
        root.right.right.right = new Node(24);
 
        int start = 14;
 
        // Function call
        int result = AmountOfTime(root, start);
        Console.WriteLine(result);
    }
}


Javascript




class GFG {
    constructor(val) {
        this.val = val;
        this.left = null;
        this.right = null;
    }
}
// A global variable to store the
// special node
let node = null;
// Function to find the
// parent-root relationship
function findParent(root, p, parent, start) {
    if (root === null) return;
    parent[root.val] = p;
    if (root.val === start) {
        node = root;
    }
    findParent(root.left, root, parent, start);
    findParent(root.right, root, parent, start);
}
// Function to return the minimum amount of time
function amountOfTime(root, start) {
    const parent = Array(100005).fill(null);
    findParent(root, null, parent, start);
    const visited = Array(100005).fill(false);
    let result = 0;
    function dfs(curr, dist) {
        visited[curr.val] = true;
        result = Math.max(result, dist);
        for (const child of [curr.left, curr.right, parent[curr.val]]) {
            if (child && !visited[child.val]) {
                dfs(child, dist + 1);
            }
        }
    }
    dfs(node, 0);
    return result;
}
// Driver Code
(function main() {
    /*      10
           /  \
          12  13
              / \
             14 15
            / \ / \
          21 22 23 24
    */
    const root = new GFG(10);
    root.left = new GFG(12);
    root.right = new GFG(13);
    root.right.left = new GFG(14);
    root.right.right = new GFG(15);
    root.right.left.left = new GFG(21);
    root.right.left.right = new GFG(22);
    root.right.right.left = new GFG(23);
    root.right.right.right = new GFG(24);
    const start = 14;
    // Function call
    const result = amountOfTime(root, start);
    console.log(result);
})();


Output

3




Time complexity: O(N),where N is the number of nodes in the binary tree, as it visits each node once.  
Space complexity:  O(N),because it uses a vector of Node pointers called “parent” with size 100005 to store the parent nodes of each node in the binary tree.

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

RELATED ARTICLES

Most Popular

Recent Comments