Minimum Time to Collect All Apples in a Tree solution and explanation
9 more videos on this problem
Minimum Time to Collect All Apples in a Tree - Leetcode 1443 - PythonNeetCodeIO · 12:25 · 25K views
1443. Minimum Time to Collect All Apples in a Tree | English | MediumSimple Code - 단순코드 · 8:58 · 2K views
1443. Minimum Time to Collect All Apples in a Tree [LeetCode]Hot Rod Gaming · 6:00 · 1K views
1443. Minimum Time to Collect All Apples in a Tree (Leetcode Medium)Programming Live with Larry · 17:19 · 1K views
Daily Leetcode #1016: Jan 11, 2023 - 1443. Minimum Time to Collect All Apples in a TreeProgramming Live with Larry · 10:51 · 1K views
Minimum Time to Collect All Apples in a Tree - DFS - PythonCheatCode Ninja · 6:35 · 561 views
1443. Minimum Time to Collect All Apples in a Tree | JavaScript | DFS | LeetCode Daily ChallengeLeetCodeWithMonu · 16:05 · 488 views
Leetcode 1443 Minimum Time to Collect All Apples in a Tree (Java) - SIMPLE CODETheAnalyticGuy · 9:16 · 471 views
Solving Leetcode 1443. Minimum Time to Collect All Apples in a TreeDaily Leetcode · 32:08 · 221 views
Leetcode 1443: Minimum Time to Collect All Apples in a TreeAlgorithms Casts · 10:02 · 218 views
The problem
Given an undirected tree consisting of n vertices numbered from 0 to n-1, which has some apples in their vertices. You spend 1 second to walk over one edge of the tree. Return the minimum time in seconds you have to spend to collect all apples in the tree, starting at vertex 0 and coming back to this vertex.
The edges of the undirected tree are given in the array edges, where edges[i] = [ai, bi] means that exists an edge connecting the vertices ai and bi. Additionally, there is a boolean array hasApple, where hasApple[i] = true means that vertex i has an apple; otherwise, it does not have any apple.
Example 1:
Input: n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,true,false,true,true,false] Output: 8 Explanation: The figure above represents the given tree where red vertices have an apple. One optimal path to collect all apples is shown by the green arrows.
Example 2:
Input: n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,true,false,false,true,false] Output: 6 Explanation: The figure above represents the given tree where red vertices have an apple. One optimal path to collect all apples is shown by the green arrows.
Example 3:
Input: n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,false,false,false,false,false] Output: 0
Constraints:
1 <= n <= 105edges.length == n - 1edges[i].length == 20 <= ai < bi <= n - 1hasApple.length == n
Approach overview
Problem Overview: You are given an undirected tree with n nodes where some nodes contain apples. Starting from node 0, you must collect every apple and return to the root. Each edge traversal costs 1 second. The goal is to compute the minimum time needed to visit all apple nodes and return.
Approach 1: DFS Traversal with Backtracking (O(n) time, O(n) space)
The tree structure naturally fits a depth-first traversal. Build an adjacency list for the graph, then run DFS from node 0. Each recursive call explores child nodes while skipping the parent to avoid revisiting edges. The key insight: only add traversal cost if a subtree contains an apple. If a child subtree returns a positive cost or the child node itself has an apple, you add 2 seconds to account for traveling to that child and returning. Otherwise, skip that branch entirely. This selective accumulation ensures you only traverse edges that lead to apples. DFS works well because it aggregates information bottom‑up: each subtree reports whether collecting apples below it required travel.
This approach relies heavily on tree traversal and recursive aggregation, a common pattern in problems involving subtree properties. You process each node once, so time complexity stays linear.
Approach 2: BFS Alternative Strategy (O(n) time, O(n) space)
A breadth-first strategy can solve the problem by first building parent relationships from the root using BFS. After constructing the parent map, iterate through all nodes that contain apples and trace the path back to the root. Mark edges that must be used to reach these apples. A set or boolean structure tracks visited edges so shared paths are counted only once. Each unique edge required for collecting apples contributes 2 seconds because you travel down and back along that edge.
This method uses breadth-first search for tree exploration and leverages parent pointers to reconstruct paths efficiently. Compared to DFS, it separates graph traversal from cost calculation. The logic is sometimes easier to visualize but requires additional structures to track visited edges.
Recommended for interviews: DFS with backtracking is the expected solution. Interviewers want to see you recognize that the graph is a tree and that only subtrees containing apples should contribute to the traversal cost. The bottom‑up aggregation pattern is common in depth-first search tree problems. BFS works but adds unnecessary bookkeeping, while DFS expresses the logic more directly.
Approach 1: DFS Traversal with Backtracking
This approach involves using Depth-First Search (DFS) to traverse the tree from the root node (vertex 0). We recursively explore each subtree from the current node. If a subtree contains any apples, we add the cost of traversing to and from that subtree (2 units of time per edge, as we have to go there and come back). This ensures that the solution captures only the necessary paths contributing to the apple collection.
class Solution:
def minTime(self, n, edges, hasApple):
from collections import defaultdict
adj = defaultdict(list)
for u, v in edges:
adj[u].append(v)
adj[v].append(u)
return self.dfs(0, -1, adj, hasApple)
def dfs(self, node, parent, adj, hasApple):
total_time = 0
for child in adj[node]:
if child == parent:
continue
child_time = self.dfs(child, node, adj, hasApple)
if child_time > 0 or hasApple[child]:
total_time += child_time + 2
return total_timeimport java.util.ArrayList;
import java.util.List;
class Solution {
public int minTime(int n, int[][] edges, List<Boolean> hasApple) {
List<List<Integer>> adj = new ArrayList<>();
for (int i = 0; i < n; i++) {
adj.add(new ArrayList<>());
}
for (int[] edge : edges) {
adj.get(edge[0]).add(edge[1]);
adj.get(edge[1]).add(edge[0]);
}
return dfs(0, -1, adj, hasApple);
}
private int dfs(int node, int parent, List<List<Integer>> adj, List<Boolean> hasApple) {
int total_time = 0;
for (int child : adj.get(node)) {
if (child == parent) continue;
int child_time = dfs(child, node, adj, hasApple);
if (child_time > 0 || hasApple.get(child)) {
total_time += child_time + 2;
}
}
return total_time;
}
}#include <vector>
using namespace std;
class Solution {
public:
int minTime(int n, vector<vector<int>>& edges, vector<bool>& hasApple) {
vector<vector<int>> adj(n);
for (auto& edge : edges) {
adj[edge[0]].push_back(edge[1]);
adj[edge[1]].push_back(edge[0]);
}
return dfs(0, -1, adj, hasApple);
}
int dfs(int node, int parent, vector<vector<int>>& adj, vector<bool>& hasApple) {
int total_time = 0;
for (int child : adj[node]) {
if (child == parent) continue;
int child_time = dfs(child, node, adj, hasApple);
if (child_time > 0 || hasApple[child]) total_time += child_time + 2;
}
return total_time;
}
};var minTime = function(n, edges, hasApple) {
const adj = Array.from({ length: n }, () => []);
for (const [u, v] of edges) {
adj[u].push(v);
adj[v].push(u);
}
return dfs(0, -1, adj, hasApple);
};
function dfs(node, parent, adj, hasApple) {
let total_time = 0;
for (const child of adj[node]) {
if (child === parent) continue;
const child_time = dfs(child, node, adj, hasApple);
if (child_time > 0 || hasApple[child]) {
total_time += child_time + 2;
}
}
return total_time;
}#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int timeRequired = 0;
void dfs(int node, int parent, int** adjList, int* adjSize, bool* hasApple) {
for (int i = 0; i < adjSize[node]; ++i) {
int child = adjList[node][i];
if (child == parent) continue;
dfs(child, node, adjList, adjSize, hasApple);
if (hasApple[child]) {
timeRequired += 2;
hasApple[node] = true;
}
}
}
int minTime(int n, int** edges, int edgesSize, bool* hasApple) {
int* adjSize = (int*)calloc(n, sizeof(int));
int** adjList = (int**)malloc(n * sizeof(int*));
for (int i = 0; i < n; ++i) {
adjList[i] = (int*)malloc((n - 1) * sizeof(int));
}
for (int i = 0; i < edgesSize; ++i) {
int u = edges[i][0];
int v = edges[i][1];
adjList[u][adjSize[u]++] = v;
adjList[v][adjSize[v]++] = u;
}
dfs(0, -1, adjList, adjSize, hasApple);
for (int i = 0; i < n; ++i) {
free(adjList[i]);
}
free(adjList);
free(adjSize);
return timeRequired;
}using System;
using System.Collections.Generic;
public class Solution {
public int MinTime(int n, int[][] edges, IList<bool> hasApple) {
List<int>[] adj = new List<int>[n];
for (int i = 0; i < n; i++) adj[i] = new List<int>();
foreach (var edge in edges) {
adj[edge[0]].Add(edge[1]);
adj[edge[1]].Add(edge[0]);
}
return DFS(0, -1, adj, hasApple);
}
private int DFS(int node, int parent, List<int>[] adj, IList<bool> hasApple) {
int total_time = 0;
foreach (int child in adj[node]) {
if (child == parent) continue;
int child_time = DFS(child, node, adj, hasApple);
if (child_time > 0 || hasApple[child]) {
total_time += child_time + 2;
}
}
return total_time;
}
}In the Python solution, DFS is used via recursion and defaultdict for efficient adjacency list storage. The code checks paths recursively, only adding travel time for paths that need accessing due to apples.
Time Complexity: O(n).
Space Complexity: O(n), defined by adjacency and recursion stack.
Approach 2: BFS Alternative Strategy
Though less intuitive for this problem compared to DFS, a Breadth-First Search (BFS) approach can be implemented to calculate the shortest paths considering leaf nodes. This method explores layers of the tree level by level but is not more efficient in this specific context than DFS, given that we only need to find necessary paths.
/* Python's theoretical BFS equivalent involves queue usage. DFS is preferred, with its path-specific application. *//* Java BFS using a queue and tracking visited nodes. Relies on comparison in broader algorithms, but DFS remains efficient for path decisions here. *//* Similar note on C++ for BFS: Iterative approach using a queue structure. DFS remains more efficient and practical in this tree scenario. *//* JavaScript's BFS hypothetical involves queue patterns not optimal here versus DFS offering precise path-recursivity. *//* BFS approach is typically less optimal for this problem due to the nature of finding paths, thus not usually implemented. For consideration of completeness, a general template would involve a queue to explore nodes layer-wise. Ideal use here remains DFS. *//* C# consideration of BFS utilizes a while-loop and queue but is secondary to the DFS primary usage for path-targeted efficiency. */DFS fits the recursive, path-specific needs over BFS here, which tracks broader levels.
Time Complexity: O(n).
Space Complexity: O(n), due to queue footprint.
Approach 3: Default Approach
func minTime(n int, edges [][]int, hasApple []bool) int {
vis := make([]bool, n)
g := make([][]int, n)
for _, e := range edges {
u, v := e[0], e[1]
g[u] = append(g[u], v)
g[v] = append(g[v], u)
}
var dfs func(int, int) int
dfs = func(u, cost int) int {
if vis[u] {
return 0
}
vis[u] = true
nxt := 0
for _, v := range g[u] {
nxt += dfs(v, 2)
}
if !hasApple[u] && nxt == 0 {
return 0
}
return cost + nxt
}
return dfs(0, 0)
}Complexity comparison
| Approach | Complexity |
|---|---|
| DFS Traversal with Backtracking | Time Complexity: O(n). |
| BFS Alternative Strategy | Time Complexity: O(n). |
| Default Approach | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| DFS Traversal with Backtracking | O(n) | O(n) | Best general solution for tree problems where subtree information determines whether edges should be included |
| BFS with Parent Path Reconstruction | O(n) | O(n) | Useful when parent relationships or level-order traversal are already required |
Frequently asked questions
Is Minimum Time to Collect All Apples in a Tree easy or hard?
The problem is classified as Medium because it requires recognizing a tree traversal pattern and implementing conditional cost accumulation. The DFS logic is straightforward once you realize that only subtrees containing apples should contribute to the total traversal time.
Minimum Time to Collect All Apples in a Tree Python/Java solution
In Python or Java, build an adjacency list from the edges and run a DFS starting at node 0. Each recursive call returns the time needed for its subtree. If a child subtree requires time or contains an apple, add 2 seconds to include that edge in the traversal. The total aggregated value is the answer.
How to solve Minimum Time to Collect All Apples in a Tree in O(n)?
Construct an adjacency list for the tree and perform a DFS from node 0. For each child subtree, recursively compute the time required to collect apples. If the subtree contains an apple or requires traversal time, add 2 seconds for the round trip along that edge. Summing these costs across relevant subtrees gives the minimum time.
What is the best approach for Minimum Time to Collect All Apples in a Tree?
DFS traversal with backtracking is the most efficient and commonly expected approach. Starting from the root, recursively explore each subtree and only add traversal cost if the subtree contains at least one apple. This ensures unnecessary branches are skipped and each node is processed once, resulting in O(n) time complexity.
Is Minimum Time to Collect All Apples in a Tree asked at Google/Amazon/Meta?
Tree traversal problems like this frequently appear in interviews at companies such as Amazon, Google, and Meta. The question tests DFS reasoning, graph representation with adjacency lists, and the ability to aggregate results from subtrees efficiently.
What data structure is used in Minimum Time to Collect All Apples in a Tree?
The solution primarily uses an adjacency list to represent the tree graph. DFS recursion or a stack processes nodes, while arrays or lists track whether each node contains an apple. In alternative strategies, BFS queues and parent maps may also be used.
What is the time complexity of Minimum Time to Collect All Apples in a Tree?
The optimal solution runs in O(n) time because each node and edge in the tree is visited once during traversal. Building the adjacency list also takes O(n). Space complexity is O(n) due to the adjacency list and recursion stack used in DFS.
