2581. Count Number of Possible Root Nodes
Problem Description
Alice has an undirected tree with n nodes labeled from 0 to n - 1. The tree is given as a 2D array edges where edges[i] = [ai, bi] indicates an edge between nodes ai and bi.
Alice wants Bob to find which node is the root of her tree. Bob makes several guesses about the parent-child relationships in the tree. Each guess consists of:
- Choosing two distinct integers 
uandvwhere an edge[u, v]exists in the tree - Claiming that 
uis the parent ofv(meaninguis closer to the root thanv) 
Bob's guesses are given as a 2D array guesses where guesses[j] = [uj, vj] means Bob guessed that uj is the parent of vj.
Alice tells Bob that at least k of his guesses are correct.
The task is to find how many different nodes could possibly be the root of Alice's tree, given that at least k of Bob's guesses must be true. Return 0 if no such tree exists.
For example, if Bob guesses that node 1 is the parent of node 2, this guess would be correct if:
- The root is node 1 (or any node where 1 is closer to the root than 2)
 - The path from the root to node 2 passes through node 1
 
The key insight is that changing which node is the root changes which parent-child relationships are true in the tree. A guess [u, v] is correct for a particular root if, when traversing from that root, we reach u before v along the path to v.
Flowchart Walkthrough
First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:
Is it a graph?
- Yes: The problem explicitly involves an undirected tree with 
nnodes and edges connecting them. A tree is a special type of graph (connected and acyclic). 
Is it a tree?
- Yes: The problem states we have an undirected tree with 
nnodes andn-1edges, which is the definition of a tree structure. 
DFS
- Yes: Since we're dealing with a tree structure, DFS (Depth-First Search) is the appropriate algorithm.
 
Conclusion: The flowchart leads us directly to using DFS for this tree problem.
Why DFS is the Right Choice
The problem requires us to:
- Traverse the tree to count how many of Bob's guesses are correct when different nodes are chosen as the root
 - Efficiently re-root the tree and recalculate the count of correct guesses
 
DFS is ideal here because:
- We need to traverse the entire tree structure from different potential root nodes
 - We need to maintain parent-child relationships as we traverse
 - The re-rooting technique (also known as "rerooting DP" or "tree DP with root change") naturally uses DFS to:
- First DFS: Calculate the initial count of correct guesses with node 0 as root
 - Second DFS: Dynamically adjust the count as we conceptually move the root to each node
 
 
The solution uses two DFS traversals:
dfs1: Counts correct guesses when node 0 is the rootdfs2: Reuses the count from the parent node and adjusts it based on edge direction changes when moving the root from parent to child
Intuition
The key insight is that when we change which node is the root of a tree, the parent-child relationships change throughout the tree. However, we don't need to rebuild the entire tree for each potential root - we can be clever about it.
Let's think about what happens when Bob makes a guess [u, v] (meaning u is the parent of v):
- This guess is correct only if, in the rooted tree, node 
uis actually on the path from the root to nodev, anduis one step closer to the root thanv. - In other words, there must be a directed edge from 
utovwhen we orient the tree edges away from the root. 
Now, here's the clever part: instead of checking all n nodes as potential roots independently (which would be inefficient), we can use a technique called "rerooting" or "tree DP with root change."
Start by picking any node as the initial root (say node 0). Count how many of Bob's guesses are correct with this root. Let's call this count cnt.
When we move the root from a node i to its adjacent node j, only the edge between i and j changes direction:
- Before: 
iis the parent ofj(edge goes fromitoj) - After: 
jis the parent ofi(edge goes fromjtoi) 
This means:
- If Bob guessed 
[i, j], this guess was correct before but incorrect after moving the root, so we subtract 1 fromcnt - If Bob guessed 
[j, i], this guess was incorrect before but correct after moving the root, so we add 1 tocnt 
By doing a DFS traversal and updating cnt as we "move" the root through the tree, we can efficiently calculate the number of correct guesses for each possible root. We count how many nodes give us at least k correct guesses.
The formula for updating the count when moving root from i to j is:
new_cnt = old_cnt - (guess[i,j] exists ? 1 : 0) + (guess[j,i] exists ? 1 : 0)
This approach runs in O(n) time since we visit each node once in each DFS, making it much more efficient than the naive O(n²) approach of rebuilding the tree for each potential root.
Learn more about Tree, Depth-First Search and Dynamic Programming patterns.
Solution Approach
The solution implements the tree DP with root change technique using two DFS traversals:
Step 1: Build the Graph and Process Guesses
- Convert the edge list to an adjacency list 
gwhereg[i]contains all nodes adjacent to nodei - Store all guesses in a hash map 
gsas(parent, child)pairs for O(1) lookup 
g = defaultdict(list)
for a, b in edges:
    g[a].append(b)
    g[b].append(a)
gs = Counter((u, v) for u, v in guesses)
Step 2: First DFS - Count Correct Guesses with Node 0 as Root
The dfs1 function traverses the tree with node 0 as the root and counts how many guesses are correct:
- For each edge 
(i, j)whereiis the parent ofj, check if this guess exists ings - If 
(i, j)is ings, increment the countercnt 
def dfs1(i, fa):
    nonlocal cnt
    for j in g[i]:
        if j != fa:  # Avoid going back to parent
            cnt += gs[(i, j)]  # Check if this parent-child guess exists
            dfs1(j, i)  # Recursively process child with i as parent
Step 3: Second DFS - Reroot and Count Valid Roots
The dfs2 function performs the rerooting technique:
- Start with the count from node 0 as root
 - For each node, check if 
cnt >= kto determine if it's a valid root - When moving the root from node 
ito its childj:- The edge 
(i, j)reverses to(j, i) - Subtract 1 if guess 
(i, j)exists (was correct, now incorrect) - Add 1 if guess 
(j, i)exists (was incorrect, now correct) 
 - The edge 
 
def dfs2(i, fa):
    nonlocal ans, cnt
    ans += cnt >= k  # Count this node if it has enough correct guesses
    for j in g[i]:
        if j != fa:
            # Adjust count for moving root from i to j
            cnt -= gs[(i, j)]  # Remove the i->j guess
            cnt += gs[(j, i)]  # Add the j->i guess
          
            dfs2(j, i)  # Process with j as potential root
          
            # Restore count when backtracking
            cnt -= gs[(j, i)]
            cnt += gs[(i, j)]
The restoration step is crucial - after exploring the subtree rooted at j, we need to restore cnt to its original value before processing the next child of i.
Time Complexity: O(n + m) where n is the number of nodes and m is the number of guesses
Space Complexity: O(n + m) for storing the graph and guess hash map
The beauty of this approach is that we only need to track the changes in count as we conceptually move the root, rather than recalculating everything from scratch for each potential root.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach.
Example Input:
- Tree edges: 
[[0,1], [1,2], [1,3]](forms a tree with node 1 connected to 0, 2, and 3) - Bob's guesses: 
[[1,2], [0,1], [3,1]](Bob guesses 1â2, 0â1, and 3â1 are parent-child relationships) - k = 2 (at least 2 guesses must be correct)
 
Tree Structure:
0 | 1 / \ 2 3
Step 1: Build Graph and Process Guesses
- Graph adjacency list: 
{0: [1], 1: [0,2,3], 2: [1], 3: [1]} - Guess map: 
{(1,2): 1, (0,1): 1, (3,1): 1} 
Step 2: First DFS with Root = 0 Starting from node 0, we traverse and count correct guesses:
- Visit 0 â 1: Check if (0,1) is a guess? Yes! 
cnt = 1 - From 1, visit 1 â 2: Check if (1,2) is a guess? Yes! 
cnt = 2 - From 1, visit 1 â 3: Check if (1,3) is a guess? No. 
cnt = 2 
With node 0 as root, 2 guesses are correct: (0,1) and (1,2).
Step 3: Second DFS - Reroot and Check Each Node
Starting at node 0 with cnt = 2:
- Node 0: 
cnt = 2 >= 2â Valid root!ans = 1 
Move root from 0 to 1:
- Edge (0,1) reverses to (1,0)
 - Remove guess (0,1): 
cnt = 2 - 1 = 1 - Add guess (1,0): Not in guesses, so 
cnt = 1 + 0 = 1 - Node 1: 
cnt = 1 < 2â Not valid 
Move root from 1 to 2:
- Edge (1,2) reverses to (2,1)
 - Remove guess (1,2): 
cnt = 1 - 1 = 0 - Add guess (2,1): Not in guesses, so 
cnt = 0 + 0 = 0 - Node 2: 
cnt = 0 < 2â Not valid - Backtrack: Restore 
cnt = 1 
Move root from 1 to 3:
- Edge (1,3) reverses to (3,1)
 - Remove guess (1,3): Not in guesses, so 
cnt = 1 - 0 = 1 - Add guess (3,1): Yes, it's a guess! 
cnt = 1 + 1 = 2 - Node 3: 
cnt = 2 >= 2â Valid root!ans = 2 
Result: 2 nodes (0 and 3) can be valid roots.
Verification:
- With root = 0: Correct guesses are (0,1) and (1,2) = 2 correct â
 - With root = 3: Correct guesses are (3,1) and (1,2) = 2 correct â
 - With root = 1: Only (1,2) is correct = 1 correct â
 - With root = 2: Only (0,1) is correct = 1 correct â
 
The rerooting technique efficiently found that nodes 0 and 3 satisfy the requirement of having at least k=2 correct guesses.
Solution Implementation
1from typing import List
2from collections import defaultdict, Counter
3
4
5class Solution:
6    def rootCount(
7        self, edges: List[List[int]], guesses: List[List[int]], k: int
8    ) -> int:
9        # Build adjacency list for the tree
10        graph = defaultdict(list)
11        for node_a, node_b in edges:
12            graph[node_a].append(node_b)
13            graph[node_b].append(node_a)
14      
15        # Convert guesses to a set/counter for O(1) lookup
16        # Each guess is a directed edge (parent, child)
17        guess_set = Counter((parent, child) for parent, child in guesses)
18      
19        # First DFS: Count correct guesses when root is node 0
20        correct_count = 0
21      
22        def count_correct_guesses(node: int, parent: int) -> None:
23            """
24            Count how many guesses are correct when treating node 0 as root.
25            A guess (u, v) is correct if u is parent of v in the rooted tree.
26            """
27            nonlocal correct_count
28          
29            for neighbor in graph[node]:
30                if neighbor != parent:
31                    # Check if edge from node to neighbor matches any guess
32                    if (node, neighbor) in guess_set:
33                        correct_count += guess_set[(node, neighbor)]
34                    # Recursively process the subtree
35                    count_correct_guesses(neighbor, node)
36      
37        # Initial count with node 0 as root
38        count_correct_guesses(0, -1)
39      
40        # Second DFS: Re-root the tree and count valid roots
41        valid_roots = 0
42      
43        def reroot_and_count(node: int, parent: int) -> None:
44            """
45            Use rerooting technique to efficiently count correct guesses
46            for each possible root without recalculating from scratch.
47            """
48            nonlocal valid_roots, correct_count
49          
50            # Check if current node as root has at least k correct guesses
51            if correct_count >= k:
52                valid_roots += 1
53          
54            # Try each child as the new root
55            for neighbor in graph[node]:
56                if neighbor != parent:
57                    # When moving root from node to neighbor:
58                    # - Edge (node, neighbor) changes from parent->child to child->parent
59                    # - Lose correct guess if (node, neighbor) was guessed
60                    # - Gain correct guess if (neighbor, node) was guessed
61                  
62                    # Update count before recursion
63                    correct_count -= guess_set.get((node, neighbor), 0)
64                    correct_count += guess_set.get((neighbor, node), 0)
65                  
66                    # Recursively process with neighbor as new root
67                    reroot_and_count(neighbor, node)
68                  
69                    # Restore count after recursion (backtrack)
70                    correct_count += guess_set.get((node, neighbor), 0)
71                    correct_count -= guess_set.get((neighbor, node), 0)
72      
73        # Start rerooting from node 0
74        reroot_and_count(0, -1)
75      
76        return valid_roots
771class Solution {
2    // Graph adjacency list representation
3    private List<Integer>[] graph;
4    // Map to store guesses: key is encoded edge (parent -> child), value is count
5    private Map<Long, Integer> guessMap = new HashMap<>();
6    // Count of valid root nodes
7    private int validRootCount;
8    // Minimum correct guesses threshold
9    private int threshold;
10    // Current count of correct guesses
11    private int correctGuessCount;
12    // Number of nodes in the tree
13    private int nodeCount;
14
15    public int rootCount(int[][] edges, int[][] guesses, int k) {
16        this.threshold = k;
17        this.nodeCount = edges.length + 1;
18      
19        // Initialize adjacency list for undirected graph
20        graph = new List[nodeCount];
21        Arrays.setAll(graph, index -> new ArrayList<>());
22      
23        // Build the undirected graph from edges
24        for (int[] edge : edges) {
25            int nodeA = edge[0];
26            int nodeB = edge[1];
27            graph[nodeA].add(nodeB);
28            graph[nodeB].add(nodeA);
29        }
30      
31        // Store all guesses in a map for O(1) lookup
32        // Each guess represents a directed edge (parent -> child)
33        for (int[] guess : guesses) {
34            int parent = guess[0];
35            int child = guess[1];
36            guessMap.merge(encodeEdge(parent, child), 1, Integer::sum);
37        }
38      
39        // First DFS: Calculate correct guesses when node 0 is root
40        calculateInitialCorrectGuesses(0, -1);
41      
42        // Second DFS: Re-root the tree and count valid roots
43        countValidRoots(0, -1);
44      
45        return validRootCount;
46    }
47
48    /**
49     * First DFS to calculate the number of correct guesses when node 0 is the root
50     * @param currentNode Current node being visited
51     * @param parent Parent of the current node (-1 if root)
52     */
53    private void calculateInitialCorrectGuesses(int currentNode, int parent) {
54        for (int child : graph[currentNode]) {
55            if (child != parent) {
56                // Check if the edge (currentNode -> child) is a correct guess
57                correctGuessCount += guessMap.getOrDefault(encodeEdge(currentNode, child), 0);
58                calculateInitialCorrectGuesses(child, currentNode);
59            }
60        }
61    }
62
63    /**
64     * Second DFS to re-root the tree and count all valid roots
65     * Uses dynamic programming to efficiently update the count when changing root
66     * @param currentNode Current node being considered as root
67     * @param parent Parent of the current node (-1 if root)
68     */
69    private void countValidRoots(int currentNode, int parent) {
70        // Check if current node as root has enough correct guesses
71        if (correctGuessCount >= threshold) {
72            validRootCount++;
73        }
74      
75        // Try each child as the new root
76        for (int child : graph[currentNode]) {
77            if (child != parent) {
78                // When moving root from currentNode to child:
79                // - Edge (currentNode -> child) becomes (child -> currentNode)
80                // - Lose correct guesses for (currentNode -> child)
81                // - Gain correct guesses for (child -> currentNode)
82              
83                int lostGuesses = guessMap.getOrDefault(encodeEdge(currentNode, child), 0);
84                int gainedGuesses = guessMap.getOrDefault(encodeEdge(child, currentNode), 0);
85              
86                // Update the count for the new root
87                correctGuessCount = correctGuessCount - lostGuesses + gainedGuesses;
88              
89                // Recursively process with child as new root
90                countValidRoots(child, currentNode);
91              
92                // Restore the count when backtracking
93                correctGuessCount = correctGuessCount - gainedGuesses + lostGuesses;
94            }
95        }
96    }
97
98    /**
99     * Encodes a directed edge into a unique long value
100     * @param from Source node
101     * @param to Destination node
102     * @return Encoded edge as a long value
103     */
104    private long encodeEdge(int from, int to) {
105        return 1L * from * nodeCount + to;
106    }
107}
1081class Solution {
2public:
3    int rootCount(vector<vector<int>>& edges, vector<vector<int>>& guesses, int k) {
4        int n = edges.size() + 1;  // Total number of nodes
5      
6        // Build adjacency list for the tree
7        vector<vector<int>> graph(n);
8        for (auto& edge : edges) {
9            int u = edge[0], v = edge[1];
10            graph[u].push_back(v);
11            graph[v].push_back(u);
12        }
13      
14        // Store guesses in a hash map for O(1) lookup
15        // Key: encoded edge (parent * n + child), Value: count
16        unordered_map<long long, int> guessMap;
17        auto encodeEdge = [&](int parent, int child) -> long long {
18            return 1LL * parent * n + child;
19        };
20      
21        for (auto& guess : guesses) {
22            int parent = guess[0], child = guess[1];
23            guessMap[encodeEdge(parent, child)]++;
24        }
25      
26        int result = 0;        // Count of valid roots
27        int correctGuesses = 0; // Current number of correct guesses
28      
29        // First DFS: Calculate correct guesses when node 0 is the root
30        function<void(int, int)> calculateInitialGuesses = [&](int node, int parent) {
31            for (int child : graph[node]) {
32                if (child != parent) {
33                    // Check if this parent-child relationship matches a guess
34                    correctGuesses += guessMap[encodeEdge(node, child)];
35                    calculateInitialGuesses(child, node);
36                }
37            }
38        };
39      
40        // Second DFS: Re-root the tree and count valid roots
41        function<void(int, int)> rerootAndCount = [&](int node, int parent) {
42            // Check if current node as root has at least k correct guesses
43            if (correctGuesses >= k) {
44                result++;
45            }
46          
47            // Try each child as the new root
48            for (int child : graph[node]) {
49                if (child != parent) {
50                    // When moving root from node to child:
51                    // - Edge (node -> child) becomes (child -> node)
52                    int lostGuesses = guessMap[encodeEdge(node, child)];  // Lost when edge flips
53                    int gainedGuesses = guessMap[encodeEdge(child, node)]; // Gained when edge flips
54                  
55                    // Update correct guess count
56                    correctGuesses = correctGuesses - lostGuesses + gainedGuesses;
57                  
58                    // Recursively process with child as new root
59                    rerootAndCount(child, node);
60                  
61                    // Restore correct guess count when backtracking
62                    correctGuesses = correctGuesses - gainedGuesses + lostGuesses;
63                }
64            }
65        };
66      
67        // Start with node 0 as root
68        calculateInitialGuesses(0, -1);
69        rerootAndCount(0, -1);
70      
71        return result;
72    }
73};
741/**
2 * Counts the number of valid root nodes based on edges and guesses
3 * @param edges - Array of edge connections in the tree
4 * @param guesses - Array of guessed parent-child relationships
5 * @param k - Minimum number of correct guesses required
6 * @returns Number of valid root nodes
7 */
8function rootCount(edges: number[][], guesses: number[][], k: number): number {
9    const nodeCount = edges.length + 1;
10  
11    // Build adjacency list for the tree
12    const adjacencyList: number[][] = Array.from({ length: nodeCount }, () => []);
13  
14    // Store guesses as a map for O(1) lookup
15    // Key: encoded edge (parent * nodeCount + child), Value: count
16    const guessMap: Map<number, number> = new Map();
17  
18    // Helper function to encode an edge into a single number
19    const encodeEdge = (parent: number, child: number): number => {
20        return parent * nodeCount + child;
21    };
22  
23    // Build the bidirectional graph from edges
24    for (const [nodeA, nodeB] of edges) {
25        adjacencyList[nodeA].push(nodeB);
26        adjacencyList[nodeB].push(nodeA);
27    }
28  
29    // Store all guesses in the map
30    for (const [parent, child] of guesses) {
31        const encodedEdge = encodeEdge(parent, child);
32        guessMap.set(encodedEdge, (guessMap.get(encodedEdge) || 0) + 1);
33    }
34  
35    let validRootCount = 0;
36    let correctGuessCount = 0;
37  
38    /**
39     * First DFS: Calculate correct guesses when node 0 is the root
40     * @param currentNode - Current node being visited
41     * @param parentNode - Parent of the current node (-1 for root)
42     */
43    const calculateInitialGuesses = (currentNode: number, parentNode: number): void => {
44        for (const childNode of adjacencyList[currentNode]) {
45            if (childNode !== parentNode) {
46                // Check if this edge matches any guess
47                correctGuessCount += guessMap.get(encodeEdge(currentNode, childNode)) || 0;
48                calculateInitialGuesses(childNode, currentNode);
49            }
50        }
51    };
52  
53    /**
54     * Second DFS: Re-root the tree and count valid roots
55     * @param currentNode - Current node being considered as root
56     * @param parentNode - Parent of the current node (-1 for initial root)
57     */
58    const countValidRoots = (currentNode: number, parentNode: number): void => {
59        // Check if current node as root has enough correct guesses
60        if (correctGuessCount >= k) {
61            validRootCount++;
62        }
63      
64        for (const childNode of adjacencyList[currentNode]) {
65            if (childNode !== parentNode) {
66                // When moving root from currentNode to childNode:
67                // - Edge (currentNode -> childNode) becomes (childNode -> currentNode)
68                const forwardEdgeCount = guessMap.get(encodeEdge(currentNode, childNode)) || 0;
69                const reverseEdgeCount = guessMap.get(encodeEdge(childNode, currentNode)) || 0;
70              
71                // Update correct guess count for the new root
72                correctGuessCount -= forwardEdgeCount;
73                correctGuessCount += reverseEdgeCount;
74              
75                // Recursively check childNode as root
76                countValidRoots(childNode, currentNode);
77              
78                // Restore correct guess count when backtracking
79                correctGuessCount -= reverseEdgeCount;
80                correctGuessCount += forwardEdgeCount;
81            }
82        }
83    };
84  
85    // Start with node 0 as root to calculate initial correct guesses
86    calculateInitialGuesses(0, -1);
87  
88    // Try each node as root and count valid ones
89    countValidRoots(0, -1);
90  
91    return validRootCount;
92}
93Time and Space Complexity
Time Complexity: O(n + m)
The algorithm consists of building the graph and two DFS traversals:
- Building the adjacency list 
gfrom edges takesO(n)time wherenis the number of edges - Creating the Counter 
gsfrom guesses takesO(m)time wheremis the number of guesses dfs1traverses the entire tree once, visiting each node exactly once and checking each edge, takingO(n)timedfs2also traverses the entire tree once, visiting each node exactly once. For each edge traversed, it performs constant time operations (updatingcntby checking presence ings), takingO(n)time overall
Total time complexity: O(n) + O(m) + O(n) + O(n) = O(n + m)
Space Complexity: O(n + m)
The space usage includes:
- Adjacency list 
gstores all edges bidirectionally, usingO(n)space - Counter 
gsstores all guesses as key-value pairs, usingO(m)space - Recursion stack for DFS can go up to the height of the tree, which in worst case (skewed tree) is 
O(n) - Other variables (
cnt,ans) useO(1)space 
Total space complexity: O(n) + O(m) + O(n) = O(n + m)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Forgetting to Restore State During Backtracking
The Problem:
A critical mistake is forgetting to restore the correct_count after exploring each subtree in the rerooting phase. Without proper restoration, the count becomes corrupted and produces incorrect results for subsequent nodes.
Incorrect Code:
def reroot_and_count(node: int, parent: int) -> None:
    nonlocal valid_roots, correct_count
  
    if correct_count >= k:
        valid_roots += 1
  
    for neighbor in graph[node]:
        if neighbor != parent:
            # Update count before recursion
            correct_count -= guess_set.get((node, neighbor), 0)
            correct_count += guess_set.get((neighbor, node), 0)
          
            reroot_and_count(neighbor, node)
          
            # MISSING: Restoration of correct_count!
Why It Fails:
Without restoration, the correct_count accumulates changes incorrectly. When processing the second child of a node, it uses the modified count from the first child rather than the original count for that node.
Solution: Always restore the state after recursion:
# Update count before recursion correct_count -= guess_set.get((node, neighbor), 0) correct_count += guess_set.get((neighbor, node), 0) reroot_and_count(neighbor, node) # Restore count after recursion correct_count += guess_set.get((node, neighbor), 0) correct_count -= guess_set.get((neighbor, node), 0)
Pitfall 2: Using Wrong Data Structure for Guess Lookup
The Problem: Using a list to check if a guess exists leads to O(m) lookup time for each edge, resulting in O(n*m) overall complexity.
Incorrect Code:
# Inefficient: Using list for guesses
guesses_list = guesses  # Direct use of input list
def count_correct_guesses(node: int, parent: int) -> None:
    nonlocal correct_count
    for neighbor in graph[node]:
        if neighbor != parent:
            # O(m) operation for each edge check!
            if [node, neighbor] in guesses_list:
                correct_count += 1
Solution: Use a set or Counter for O(1) lookup:
# Efficient: Convert to set/Counter guess_set = Counter((parent, child) for parent, child in guesses) # Now checking is O(1) if (node, neighbor) in guess_set: correct_count += guess_set[(node, neighbor)]
Pitfall 3: Incorrect Edge Direction Handling
The Problem:
Confusing which edge direction represents a correct guess when rerooting. Remember that a guess (u, v) means "u is the parent of v".
Incorrect Logic:
# Wrong: Adding when should subtract, or vice versa correct_count += guess_set.get((node, neighbor), 0) # Should be subtract! correct_count -= guess_set.get((neighbor, node), 0) # Should be add!
Why It's Wrong:
When moving root from node to neighbor:
- The edge 
(node, neighbor)was a parent-child relationship (node was parent) - After rerooting, it becomes child-parent (neighbor is now parent)
 - If 
(node, neighbor)was a correct guess before, it's now incorrect - If 
(neighbor, node)was an incorrect guess before, it's now correct 
Solution: Always remember the transformation rule:
# When moving root from node to neighbor: correct_count -= guess_set.get((node, neighbor), 0) # Was correct, now wrong correct_count += guess_set.get((neighbor, node), 0) # Was wrong, now correct
Pitfall 4: Not Handling Duplicate Guesses
The Problem: If the same guess appears multiple times in the input, treating it as appearing only once will give wrong counts.
Incorrect Code:
# Using set instead of Counter loses duplicate information
guess_set = set((parent, child) for parent, child in guesses)
# This only adds 1 even if the guess appears multiple times
if (node, neighbor) in guess_set:
    correct_count += 1  # Should add the actual count!
Solution: Use Counter to preserve the count of each guess:
guess_set = Counter((parent, child) for parent, child in guesses) correct_count += guess_set[(node, neighbor)] # Adds the actual frequency
You are given an array of intervals where intervals[i] = [start_i, end_i] represent the start and end of the ith interval. You need to merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.
Recommended Readings
Everything About Trees A tree is a type of graph data structure composed of nodes and edges Its main properties are It is acyclic doesn't contain any cycles There exists a path from the root to any node Has N 1 edges where N is the number of nodes in the tree and
https assets algo monster cover_photos dfs svg Depth First Search Prereqs Recursion Review problems recursion_intro Trees problems tree_intro With a solid understanding of recursion under our belts we are now ready to tackle one of the most useful techniques in coding interviews Depth First Search DFS As the name suggests
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
Want a Structured Path to Master System Design Too? Donât Miss This!