Skip to content
JZLeetCode
Go back

LeetCode 2385 Amount of Time for Binary Tree to Be Infected

Table of contents

Open Table of contents

Description

Question Links: LeetCode 2385

You are given the root of a binary tree with unique values, and an integer start. At minute 0, an infection starts from the node with value start.

Each minute, a node becomes infected if:

Return the number of minutes needed for the entire tree to be infected.

Example 1:

        1
       / \
      5   3
     /   / \
    4   10   6
   / \
  9   2

Input: root = [1,5,3,4,null,10,6,9,2], start = 3
Output: 4
Explanation:
- Minute 0: Node 3
- Minute 1: Nodes 1, 10, 6
- Minute 2: Node 5
- Minute 3: Node 4
- Minute 4: Nodes 9, 2

Example 2:

Input: root = [1], start = 1
Output: 0

Constraints:

Idea

Solution 1: BFS (Graph Conversion)

Treat the binary tree as an undirected graph. Build parent pointers (or an adjacency list) via DFS, then BFS from the start node. The number of BFS levels minus one equals the infection time.

       1
      / \
     5   3   <-- start = 3
    /   / \
   4   10   6
  / \
 9   2

BFS from 3: level 0 = {3}
             level 1 = {1, 10, 6}
             level 2 = {5}
             level 3 = {4}
             level 4 = {9, 2}  --> answer = 4

Complexity: Time O(n)O(n), Space O(n)O(n).

Solution 2: One-Pass DFS (Negative Encoding)

Avoid building an explicit graph by using a single post-order DFS. Define depth(node):

depth(None) = 0

depth(9) = 1     depth(2) = 1
      \         /
    depth(4) = max(1,1)+1 = 2
      /
depth(5) = max(2,0)+1 = 3

depth(10) = 1    depth(6) = 1
       \        /
     depth(3): node.val==start
       ans = max(1, 1) = 1
       return -1

depth(1): left=3, right=-1
  right < 0 → ans = max(1, left - right) = max(1, 3-(-1)) = 4 ✓
  return -2

The formula left - right = left + |right| works because heights are 1-indexed: left=3 means the farthest leaf from node 5 is 3 edges away (5→4→9). Adding |right|=1 (the edge from node 1 to start’s direction) gives the total path length of 4.

Complexity: Time O(n)O(n), Space O(h)O(h) where hh is tree height.

Java

// BFS approach. O(n) time, O(n) space.
public static int amountOfTime(TreeNode root, int start) {
    Map<Integer, TreeNode> parentMap = new HashMap<>();
    Map<Integer, TreeNode> nodeMap = new HashMap<>();
    Deque<TreeNode> stack = new ArrayDeque<>();
    stack.push(root);
    // O(n) DFS to build parent pointers and node lookup
    while (!stack.isEmpty()) {
        TreeNode node = stack.pop();
        nodeMap.put(node.val, node);
        if (node.right != null) {
            parentMap.put(node.right.val, node);
            stack.push(node.right);
        }
        if (node.left != null) {
            parentMap.put(node.left.val, node);
            stack.push(node.left);
        }
    }
    // BFS from start node; O(n) time, O(n) space
    TreeNode startNode = nodeMap.get(start);
    Set<Integer> visited = new HashSet<>();
    Queue<TreeNode> queue = new ArrayDeque<>();
    queue.add(startNode);
    visited.add(start);
    int minutes = -1;
    while (!queue.isEmpty()) {
        int size = queue.size();
        minutes++;
        for (int i = 0; i < size; i++) {
            TreeNode cur = queue.poll();
            if (cur.left != null && visited.add(cur.left.val)) queue.add(cur.left);
            if (cur.right != null && visited.add(cur.right.val)) queue.add(cur.right);
            TreeNode parent = parentMap.get(cur.val);
            if (parent != null && visited.add(parent.val)) queue.add(parent);
        }
    }
    return minutes;
}
// DFS approach. O(n) time, O(h) space.
private static int ans;

public static int amountOfTimeDfs(TreeNode root, int start) {
    ans = 0;
    depth(root, start);
    return ans;
}

private static int depth(TreeNode node, int start) {
    if (node == null) return 0;
    int left = depth(node.left, start);   // O(h) stack
    int right = depth(node.right, start);

    if (node.val == start) {
        ans = Math.max(ans, Math.max(left, right));
        return -1;
    }
    if (left < 0) {
        ans = Math.max(ans, right - left);
        return left - 1;
    }
    if (right < 0) {
        ans = Math.max(ans, left - right);
        return right - 1;
    }
    return 1 + Math.max(left, right);
}

Python

class Solution:
    """BFS: build parent map, then BFS from start. O(n) time, O(n) space."""

    def amountOfTime(self, root: Optional[TreeNode], start: int) -> int:
        parent = {}
        start_node = None

        def build(node, par):  # O(n)
            nonlocal start_node
            if not node:
                return
            parent[node] = par
            if node.val == start:
                start_node = node
            build(node.left, node)
            build(node.right, node)

        build(root, None)

        queue = deque([start_node])
        visited = {start_node}
        minutes = -1
        while queue:  # O(n) total
            minutes += 1
            for _ in range(len(queue)):
                node = queue.popleft()
                for neighbor in (node.left, node.right, parent[node]):
                    if neighbor and neighbor not in visited:
                        visited.add(neighbor)
                        queue.append(neighbor)
        return minutes
class Solution2:
    """DFS: negative encoding. O(n) time, O(h) space."""

    def amountOfTime(self, root: Optional[TreeNode], start: int) -> int:
        self.ans = 0

        def depth(node):  # O(n)
            if not node:
                return 0
            left = depth(node.left)   # O(h) stack
            right = depth(node.right)

            if node.val == start:
                self.ans = max(self.ans, max(left, right))
                return -1
            if left < 0:
                self.ans = max(self.ans, right - left)
                return left - 1
            if right < 0:
                self.ans = max(self.ans, left - right)
                return right - 1
            return max(left, right) + 1

        depth(root)
        return self.ans

C++

// BFS: build parent map, then BFS from start. O(n) time, O(n) space.
int amountOfTime(TreeNode* root, int start) {
    unordered_map<TreeNode*, TreeNode*> parent;
    TreeNode* startNode = nullptr;

    function<void(TreeNode*, TreeNode*)> buildParent = [&](TreeNode* node, TreeNode* par) {
        if (!node) return;
        parent[node] = par;
        if (node->val == start) startNode = node;
        buildParent(node->left, node);
        buildParent(node->right, node);
    };
    buildParent(root, nullptr);

    queue<TreeNode*> q;
    unordered_set<TreeNode*> visited;
    q.push(startNode);
    visited.insert(startNode);
    int minutes = -1;

    while (!q.empty()) {
        int sz = q.size();
        minutes++;
        for (int i = 0; i < sz; i++) {
            TreeNode* cur = q.front(); q.pop();
            for (TreeNode* next : {cur->left, cur->right, parent[cur]}) {
                if (next && !visited.count(next)) {
                    visited.insert(next);
                    q.push(next);
                }
            }
        }
    }
    return minutes;
}
// DFS: negative encoding. O(n) time, O(h) space.
class Solution2 {
    int ans;

    int depth(TreeNode* node, int start) {
        if (!node) return 0;
        int left = depth(node->left, start);
        int right = depth(node->right, start);

        if (node->val == start) {
            ans = max(left, right);
            return -1;
        }
        if (left < 0) {
            ans = max(ans, right - left);
            return left - 1;
        }
        if (right < 0) {
            ans = max(ans, left - right);
            return right - 1;
        }
        return max(left, right) + 1;
    }

public:
    int amountOfTime(TreeNode* root, int start) {
        ans = 0;
        depth(root, start);
        return ans;
    }
};

Rust

// BFS: build adjacency list, then BFS from start. O(n) time, O(n) space.
pub fn amount_of_time(root: TreeLink, start: i32) -> i32 {
    let mut graph: HashMap<i32, Vec<i32>> = HashMap::new();

    fn build(node: &TreeLink, graph: &mut HashMap<i32, Vec<i32>>) {
        if let Some(n) = node {
            let n = n.borrow();
            if let Some(ref left) = n.left {
                let lv = left.borrow().val;
                graph.entry(n.val).or_default().push(lv);
                graph.entry(lv).or_default().push(n.val);
                build(&n.left, graph);
            }
            if let Some(ref right) = n.right {
                let rv = right.borrow().val;
                graph.entry(n.val).or_default().push(rv);
                graph.entry(rv).or_default().push(n.val);
                build(&n.right, graph);
            }
        }
    }

    build(&root, &mut graph);

    let mut visited: HashMap<i32, bool> = HashMap::new();
    let mut queue = VecDeque::new();
    queue.push_back(start);
    visited.insert(start, true);
    let mut minutes = -1;

    while !queue.is_empty() {
        let size = queue.len();
        for _ in 0..size {
            let cur = queue.pop_front().unwrap();
            if let Some(neighbors) = graph.get(&cur) {
                for &nb in neighbors {
                    if !visited.contains_key(&nb) {
                        visited.insert(nb, true);
                        queue.push_back(nb);
                    }
                }
            }
        }
        minutes += 1;
    }
    minutes
}
// DFS: negative encoding. O(n) time, O(h) space.
pub fn amount_of_time_dfs(root: TreeLink, start: i32) -> i32 {
    let mut ans = 0;

    fn depth(node: &TreeLink, start: i32, ans: &mut i32) -> i32 {
        match node {
            None => 0,
            Some(n) => {
                let n = n.borrow();
                let left = depth(&n.left, start, ans);
                let right = depth(&n.right, start, ans);

                if n.val == start {
                    *ans = left.max(right);
                    return -1;
                }
                if left < 0 {
                    *ans = (*ans).max(right - left);
                    return left - 1;
                }
                if right < 0 {
                    *ans = (*ans).max(left - right);
                    return right - 1;
                }
                left.max(right) + 1
            }
        }
    }

    depth(&root, start, &mut ans);
    ans
}
Share this post on:

Previous Post
System Design - How Filesystem Journaling Works
Next Post
LeetCode 863 All Nodes Distance K in Binary Tree