Leetcode 1443: Minimum Time to Collect All Apples in a Tree
You are given an undirected tree with
n
vertices numbered from 0
to n-1
. Some vertices in this tree contain apples. Each edge in the tree requires 1 second
to traverse. Starting at vertex 0
, determine the minimum time required to collect all apples and return to vertex 0
. The tree structure is described by the array edges
, where edges[i] = [ai, bi]
indicates an edge between vertices ai
and bi
. Additionally, the array hasApple
specifies whether a vertex contains an apple (true
) or not (false
).Problem
Approach
Steps
Complexity
Input: The number of vertices `n`, the list of edges representing the tree, and the boolean array `hasApple`.
Example: Input: n = 5, edges = [[0,1],[0,2],[1,3],[1,4]], hasApple = [false,true,true,false,false]
Constraints:
• 1 <= n <= 10^5
• edges.length == n - 1
• 0 <= ai, bi < n
• Each vertex is part of exactly one connected component.
• hasApple.length == n
Output: An integer representing the minimum time in seconds to collect all apples and return to vertex `0`.
Example: Output: 6
Constraints:
• The output must be a non-negative integer.
Goal: Find the minimum traversal time to collect all apples and return to the starting point.
Steps:
• Construct a graph from the edges.
• Use a Depth-First Search (DFS) to traverse the tree starting from vertex `0`.
• For each subtree, calculate the time required to collect apples.
• Avoid unnecessary traversal if no apples are present in a subtree.
Goal: Ensure efficient computation for large inputs.
Steps:
• Avoid revisiting nodes by using a `visited` array.
• Ensure the solution handles up to `10^5` vertices within reasonable time.
Assumptions:
• The tree is connected and acyclic.
• The input tree has exactly `n-1` edges.
• Input: Input: n = 6, edges = [[0,1],[0,2],[1,3],[2,4],[2,5]], hasApple = [false,false,true,false,true,true]
• Explanation: The optimal path involves visiting vertices 2, 4, and 5. The total time is `8` seconds.
• Input: Input: n = 4, edges = [[0,1],[0,2],[1,3]], hasApple = [false,false,false,false]
• Explanation: No apples exist, so the output is `0`.
Approach: Use Depth-First Search (DFS) to traverse the tree and calculate the minimal traversal time.
Observations:
• Traversing unnecessary paths increases the time.
• Each edge should only be traversed if it leads to an apple.
• Using DFS ensures that we only traverse relevant subtrees containing apples.
Steps:
• Construct an adjacency list representation of the tree.
• Perform a DFS starting from vertex `0`.
• For each vertex, recursively check its children.
• If any child contains an apple or leads to an apple, add `2` seconds for the traversal.
• Return the total time.
Empty Inputs:
• Input: n = 1, edges = [], hasApple = [false] -> Output: 0
Large Inputs:
• Input: n = 10^5 with a sparse distribution of apples -> Should run within time constraints.
Special Values:
• Input: All vertices have apples -> Every edge will be traversed.
Constraints:
• Ensure no cycles exist in the graph structure.
class Solution {
map<int, vector<int>> gph;
map<int, int> visited;
vector<bool> hasApple;
public:
int minTime(int n, vector<vector<int>>& edges, vector<bool>& hasApple) {
this->hasApple = hasApple;
for(auto x: edges) {
gph[x[0]].push_back(x[1]);
gph[x[1]].push_back(x[0]);
}
return dfs(0, 0);
}
int dfs(int mycost, int node) {
if(visited[node]) return 0;
visited[node] = true;
int childcost = 0;
for(int x: gph[node]) {
childcost += dfs(2, x);
}
if(childcost == 0 && hasApple[node] == false)
return 0;
return childcost + mycost;
}
1 : Class Declaration
class Solution {
Defines the `Solution` class that will contain the logic for the problem, including the graph representation and the depth-first search function.
2 : Graph Initialization
map<int, vector<int>> gph;
Declares a map `gph` to store the graph as an adjacency list, where each node points to a list of connected nodes (edges).
3 : Visited Nodes
map<int, int> visited;
Declares a map `visited` to keep track of the nodes that have been visited during the DFS traversal to avoid reprocessing the same node.
4 : Apple Nodes
vector<bool> hasApple;
Declares a vector `hasApple` to track whether a node contains an apple, where each element in the vector corresponds to a node.
5 : Access Control
public:
Marks the beginning of the public section of the class, where methods can be accessed by other parts of the program.
6 : minTime Method
int minTime(int n, vector<vector<int>>& edges, vector<bool>& hasApple) {
Defines the `minTime` method, which calculates the minimum time to collect all apples. It takes the number of nodes, a list of edges, and a list of boolean values representing nodes with apples.
7 : Apple Assignment
this->hasApple = hasApple;
Assigns the `hasApple` parameter to the class's `hasApple` member variable, enabling access to the apple information for each node.
8 : Graph Construction
for(auto x: edges) {
Iterates over each edge in the `edges` list to build the graph (adjacency list). Each edge connects two nodes, represented by `x[0]` and `x[1]`.
9 : Graph Population
gph[x[0]].push_back(x[1]);
Adds the second node `x[1]` to the adjacency list of the first node `x[0]`, establishing an undirected connection.
10 : Graph Population
gph[x[1]].push_back(x[0]);
Adds the first node `x[0]` to the adjacency list of the second node `x[1]`, completing the undirected connection between the two nodes.
11 : DFS Call
return dfs(0, 0);
Calls the `dfs` method starting from node 0 (the root) with an initial cost of 0 and returns the total time required to collect all apples.
12 : DFS Method
int dfs(int mycost, int node) {
Defines the `dfs` method, which performs a depth-first search to calculate the total time for collecting apples from a given node. It takes the current cost (`mycost`) and the node to explore (`node`).
13 : Visited Check
if(visited[node]) return 0;
Checks if the current node has already been visited. If it has, returns 0 to avoid redundant calculations.
14 : Mark as Visited
visited[node] = true;
Marks the current node as visited to prevent revisiting it in future DFS calls.
15 : Child Cost Initialization
int childcost = 0;
Initializes a variable `childcost` to accumulate the cost of traversing the child nodes.
16 : Child Node Exploration
for(int x: gph[node]) {
Iterates over all the child nodes of the current node (`node`) in the graph.
17 : Recursive DFS Call
childcost += dfs(2, x);
Makes a recursive call to `dfs` for each child node, with a cost of 2 (the fixed cost to move to a child node) and accumulates the returned `childcost`.
18 : Apple Check
if(childcost == 0 && hasApple[node] == false)
Checks if the current node has no child nodes contributing to the cost and does not contain an apple. If true, it returns 0 to indicate no further action is needed for this node.
19 : Return Zero
return 0;
Returns 0 when the current node has no apple and no child nodes contributing to the cost.
20 : Return Total Cost
return childcost + mycost;
Returns the total accumulated cost of traversing from the current node, including the cost of its child nodes and the fixed cost (`mycost`) for visiting the node.
Best Case: O(n)
Average Case: O(n)
Worst Case: O(n)
Description: Each vertex and edge is visited at most once during DFS.
Best Case: O(n)
Worst Case: O(n)
Description: The adjacency list and recursion stack require linear space.
LeetCode Solutions Library / DSA Sheets / Course Catalog |
---|
comments powered by Disqus