Facebook Pixel

3607. Power Grid Maintenance

MediumDepth-First SearchBreadth-First SearchUnion FindGraphArrayHash TableOrdered SetHeap (Priority Queue)
LeetCode ↗

Problem Description

You are given an integer c representing c power stations, each with a unique identifier id from 1 to c (1-based indexing).

These stations are connected by n bidirectional cables, given as a 2D array connections, where each connections[i] = [u_i, v_i] means there is a cable between station u_i and station v_i. Any group of stations that are directly or indirectly connected forms a power grid.

At the start, all stations are online (operational).

You are also given a 2D array queries, where each query is one of two types:

  • [1, x]: A maintenance check is requested for station x.
    • If station x is online, it handles the check by itself, so the answer is x.
    • If station x is offline, the check is handled by the operational station with the smallest id that belongs to the same power grid as x.
    • If there is no operational station in that grid, the answer is -1.
  • [2, x]: Station x goes offline (it becomes non-operational).

You must return an array of integers containing the results of every query of type [1, x], in the order they appear.

Note: Taking a station offline does not change the structure of the grid. An offline station stays part of its grid, and connectivity between stations is never affected by a station going offline.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

How We Pick the Algorithm

Why Disjoint Set Union?

This problem maps to Disjoint Set Union through a short path in the full flowchart.

Graphproblem?yesDoes theprobleminvolveyesDisjoint SetUnion

The problem groups stations into power grids using Union-Find, then maintains a sorted set of online stations per grid to answer maintenance and offline queries.

Open in Flowchart
Show step-by-step reasoning

First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:

Is it a graph?

  • Yes: The power stations are nodes, and the cables connecting them are edges. Groups of connected stations form power grids, which are essentially connected components in a graph.

Is it a tree?

  • No: The grid can contain cycles (multiple cables forming loops), and there is no guarantee of a single connected acyclic structure. We have a general graph with possibly many components.

Is the problem related to directed acyclic graphs?

  • No: The cables are bidirectional, so the graph is undirected, not directed.

Is the problem related to shortest paths?

  • No: We never measure distances or path lengths between stations. We only care about which stations belong to the same grid.

Does the problem involve connectivity?

  • Yes: The core of the problem is determining which stations are "directly or indirectly connected" into the same power grid, then querying within those connected groups.

Disjoint Set Union?

  • Yes: Connectivity between components is naturally handled by grouping stations into sets. We can traverse each component using Depth-First Search to label all stations belonging to the same grid, then maintain a sorted structure of online stations per grid to answer the queries.

Conclusion: The flowchart guides us toward a connectivity-based approach. Using Depth-First Search to identify the connected components (power grids), combined with a sorted set per grid to track online stations, lets us efficiently resolve each maintenance check and offline query.

Intuition

The key observation is that taking a station offline never changes the structure of the grid. The connections are fixed from the start, and an offline station still belongs to its power grid. This means the grouping of stations into grids is decided entirely by the connections and stays constant throughout all the queries.

So the first thing we want to know is: which stations belong to the same grid? Since two stations are in the same grid if they are directly or indirectly connected, this is simply a matter of finding connected components. We can build these groups once at the beginning, either by running a Depth-First Search from each unvisited station, or by using a Union-Find structure to merge connected stations into the same set. Every station then maps to a representative (the root) that identifies its grid.

Now look at what each query actually needs:

  • For [1, x], if x is online we just answer x. Otherwise we need the smallest id among the online stations in the same grid as x, or -1 if none remain online.
  • For [2, x], we mark station x as offline, which means it should no longer be considered when looking for the smallest online station.

This tells us that for each grid we must be able to do two things efficiently: remove a station (when it goes offline) and find the smallest remaining station (when answering a check). A plain list would be slow, but a sorted set fits perfectly. With a sorted set per grid, deletion and finding the minimum are both fast.

Putting it together: we group all stations by grid once at the start, place each station's id into the sorted set of its grid, then process the queries in order. For a check, we find the grid root of x and either return x (if still present) or the first element of that grid's sorted set (or -1 if it's empty). For an offline operation, we simply discard x from its grid's sorted set. Because the grid structure is fixed, we only ever pay for the lightweight set operations during the queries.

Pattern Learn more about Depth-First Search, Breadth-First Search, Union Find, Graph and Heap (Priority Queue) patterns.

Solution Approach

Solution 1: Union-Find + Sorted Set

We use Union-Find to maintain the connection relationships between power stations, which lets us determine the grid each station belongs to. For each grid, we keep a sorted set (such as SortedList in Python, TreeSet in Java, or std::set in C++) holding all online station IDs in that grid, so we can efficiently query and delete stations.

The specific steps are as follows:

  1. Initialize the Union-Find structure over c + 1 slots (using 1-based indexing) and process all connection relationships, merging connected stations into the same set. In the code, uf.union(u, v) merges the sets of u and v, and uf.find(x) returns the root representing the grid of station x. The union step uses union by size to keep the tree shallow, and find uses path compression for speed.

  2. Create a sorted set for each grid. We loop over every station i from 1 to c, find its grid root with uf.find(i), and add i to the sorted set st[root]. After this, each grid's sorted set contains all of its station IDs in ascending order.

  3. Iterate through the query list. For each query [a, x], first compute root = uf.find(x):

    • For a query [1, x] (a == 1):
      • If x is still online (x in st[root]), append x to the answer.
      • Otherwise, if the set is non-empty (len(st[root])), append the smallest online station st[root][0].
      • Otherwise, append -1 since no operational station remains in the grid.
    • For a query [2, x] (a == 2), call st[root].discard(x) to remove station x from its grid's sorted set, marking it offline.
  4. Finally, return all query results collected for type [1, x] queries.

Because the grid membership never changes, the heavy work of grouping is done once up front. Each query then costs only O(log m) time for the membership check, minimum lookup, or deletion on a sorted set of size m. The overall time complexity is O((c + n + q) * log c), where c is the number of stations, n is the number of connections, and q is the number of queries. The space complexity is O(c) for the Union-Find arrays and the sorted sets combined.

Example Walkthrough

Let's trace through a small example to see how the Union-Find + Sorted Set approach works.

Input:

  • c = 5 (stations with ids 1, 2, 3, 4, 5)
  • connections = [[1, 2], [2, 3], [4, 5]]
  • queries = [[1, 3], [2, 1], [1, 3], [2, 2], [1, 3], [1, 4], [2, 4], [1, 4], [2, 5], [1, 4]]

Step 1 & 2: Build the grids and sorted sets

First, we run Union-Find over the connections to discover the connected components (grids):

  • union(1, 2){1, 2} are linked
  • union(2, 3){1, 2, 3} are linked
  • union(4, 5){4, 5} are linked

This produces two grids. Suppose find returns root 1 for the first grid and root 4 for the second. We then place each station into its grid's sorted set:

Grid rootSorted set of online stations
1[1, 2, 3]
4[4, 5]

Station 5 is never queried, but it still belongs to grid 4.


Step 3: Process the queries in order

We keep an answer list ans for every [1, x] query.

QueryActionGrid set stateAnswer
[1, 3]root=1, station 3 is online (3 in {1,2,3}) → answer 3{1,2,3}, {4,5}3
[2, 1]root=1, discard 1{2,3}, {4,5}
[1, 3]root=1, station 3 is online → answer 3{2,3}, {4,5}3
[2, 2]root=1, discard 2{3}, {4,5}
[1, 3]root=1, station 3 is online → answer 3{3}, {4,5}3
[1, 4]root=4, station 4 is online → answer 4{3}, {4,5}4
[2, 4]root=4, discard 4{3}, {5}
[1, 4]root=4, station 4 is offline; set {5} non-empty → smallest 5{3}, {5}5
[2, 5]root=4, discard 5{3}, {}
[1, 4]root=4, station 4 offline; set {} empty → no station → -1{3}, {}-1

Final Result

Collecting answers from each [1, x] query in order:

[3, 3, 3, 4, 5, -1]

Key Takeaways from the Trace

  • The grid grouping ({1,2,3} and {4,5}) was computed once and never changed, even as stations went offline.
  • A [2, x] query only removes x from its grid's sorted set — it does not split the grid or alter connectivity.
  • For a [1, x] query, if x is still in its set we answer x directly; otherwise we take the smallest remaining id (st[root][0]), and fall back to -1 only when the grid has no online stations left (as seen in the last query).

Solution Implementation

1from typing import List
2from sortedcontainers import SortedList
3
4
5class UnionFind:
6    def __init__(self, n: int) -> None:
7        # parent[i] is the parent of node i; initially each node is its own parent
8        self.parent = list(range(n))
9        # size[i] is the number of nodes in the tree rooted at i (used for union by size)
10        self.size = [1] * n
11
12    def find(self, x: int) -> int:
13        # Find the root of x with path compression
14        if self.parent[x] != x:
15            self.parent[x] = self.find(self.parent[x])
16        return self.parent[x]
17
18    def union(self, a: int, b: int) -> bool:
19        # Merge the sets containing a and b; return False if already connected
20        root_a, root_b = self.find(a), self.find(b)
21        if root_a == root_b:
22            return False
23        # Union by size: attach the smaller tree under the larger tree
24        if self.size[root_a] > self.size[root_b]:
25            self.parent[root_b] = root_a
26            self.size[root_a] += self.size[root_b]
27        else:
28            self.parent[root_a] = root_b
29            self.size[root_b] += self.size[root_a]
30        return True
31
32
33class Solution:
34    def processQueries(
35        self, c: int, connections: List[List[int]], queries: List[List[int]]
36    ) -> List[int]:
37        # Build the union-find structure for stations numbered 1..c
38        uf = UnionFind(c + 1)
39        for u, v in connections:
40            uf.union(u, v)
41
42        # For each component root, keep a sorted list of its online stations
43        online_by_root = [SortedList() for _ in range(c + 1)]
44        for station in range(1, c + 1):
45            online_by_root[uf.find(station)].add(station)
46
47        ans: List[int] = []
48        for query_type, station in queries:
49            root = uf.find(station)
50            if query_type == 1:
51                # Maintenance check on the given station
52                if station in online_by_root[root]:
53                    # The station itself is online, so it can serve
54                    ans.append(station)
55                elif online_by_root[root]:
56                    # Otherwise return the smallest online station in the component
57                    ans.append(online_by_root[root][0])
58                else:
59                    # No online station available in the component
60                    ans.append(-1)
61            else:
62                # Take the given station offline by removing it from its component
63                online_by_root[root].discard(station)
64
65        return ans
66
1class UnionFind {
2    // Parent array: p[i] stores the parent of node i
3    private final int[] p;
4    // Size array: size[i] stores the size of the tree rooted at i
5    private final int[] size;
6
7    public UnionFind(int n) {
8        p = new int[n];
9        size = new int[n];
10        // Initially every node is its own root with size 1
11        for (int i = 0; i < n; ++i) {
12            p[i] = i;
13            size[i] = 1;
14        }
15    }
16
17    /**
18     * Finds the root of node x with path compression.
19     *
20     * @param x the node to query
21     * @return the root representative of the set containing x
22     */
23    public int find(int x) {
24        if (p[x] != x) {
25            // Path compression: point x directly to the root
26            p[x] = find(p[x]);
27        }
28        return p[x];
29    }
30
31    /**
32     * Merges the sets containing a and b using union by size.
33     *
34     * @param a the first node
35     * @param b the second node
36     * @return true if a merge happened, false if they were already connected
37     */
38    public boolean union(int a, int b) {
39        int pa = find(a), pb = find(b);
40        // Already in the same set, no merge needed
41        if (pa == pb) {
42            return false;
43        }
44        // Attach the smaller tree under the larger one
45        if (size[pa] > size[pb]) {
46            p[pb] = pa;
47            size[pa] += size[pb];
48        } else {
49            p[pa] = pb;
50            size[pb] += size[pa];
51        }
52        return true;
53    }
54}
55
56class Solution {
57    public int[] processQueries(int c, int[][] connections, int[][] queries) {
58        // Build the disjoint set over nodes 1..c (index 0 unused)
59        UnionFind uf = new UnionFind(c + 1);
60        for (int[] e : connections) {
61            uf.union(e[0], e[1]);
62        }
63
64        // For each connected component (keyed by its root), maintain an
65        // ordered set of currently online nodes so we can quickly fetch
66        // the smallest available node.
67        TreeSet<Integer>[] st = new TreeSet[c + 1];
68        Arrays.setAll(st, k -> new TreeSet<>());
69        for (int i = 1; i <= c; i++) {
70            int root = uf.find(i);
71            st[root].add(i);
72        }
73
74        List<Integer> ans = new ArrayList<>();
75        for (int[] q : queries) {
76            int a = q[0], x = q[1];
77            // Identify the component that node x belongs to
78            int root = uf.find(x);
79
80            if (a == 1) {
81                // Type 1 query: report a usable node in x's component
82                if (st[root].contains(x)) {
83                    // x itself is online, prefer returning x
84                    ans.add(x);
85                } else if (!st[root].isEmpty()) {
86                    // Otherwise return the smallest online node in the component
87                    ans.add(st[root].first());
88                } else {
89                    // No online node available in the component
90                    ans.add(-1);
91                }
92            } else {
93                // Type 2 query: take node x offline
94                st[root].remove(x);
95            }
96        }
97
98        // Convert the result list to a primitive int array
99        return ans.stream().mapToInt(Integer::intValue).toArray();
100    }
101}
102
1class UnionFind {
2public:
3    // Initialize the union-find structure with n elements (indices 0..n-1).
4    UnionFind(int n) {
5        parent = vector<int>(n);
6        componentSize = vector<int>(n, 1);
7        // Each element starts as its own root: parent[i] = i.
8        iota(parent.begin(), parent.end(), 0);
9    }
10
11    // Merge the sets containing a and b.
12    // Returns false if they already belong to the same set, true otherwise.
13    bool unite(int a, int b) {
14        int rootA = find(a), rootB = find(b);
15        if (rootA == rootB) {
16            return false;
17        }
18        // Union by size: attach the smaller tree under the larger one.
19        if (componentSize[rootA] > componentSize[rootB]) {
20            parent[rootB] = rootA;
21            componentSize[rootA] += componentSize[rootB];
22        } else {
23            parent[rootA] = rootB;
24            componentSize[rootB] += componentSize[rootA];
25        }
26        return true;
27    }
28
29    // Find the root representative of x with path compression.
30    int find(int x) {
31        if (parent[x] != x) {
32            parent[x] = find(parent[x]);
33        }
34        return parent[x];
35    }
36
37private:
38    vector<int> parent;         // parent[i] points to the parent of node i
39    vector<int> componentSize;  // componentSize[root] holds the size of the component
40};
41
42class Solution {
43public:
44    vector<int> processQueries(int c, vector<vector<int>>& connections, vector<vector<int>>& queries) {
45        // Build the connected components from the given connections.
46        // Use indices 1..c, so allocate c + 1 slots.
47        UnionFind uf(c + 1);
48        for (auto& edge : connections) {
49            uf.unite(edge[0], edge[1]);
50        }
51
52        // For each component root, store its online stations in a sorted set,
53        // so the smallest available station can be retrieved quickly.
54        vector<set<int>> componentStations(c + 1);
55        for (int i = 1; i <= c; i++) {
56            componentStations[uf.find(i)].insert(i);
57        }
58
59        vector<int> ans;
60        for (auto& query : queries) {
61            int type = query[0], station = query[1];
62            int root = uf.find(station);
63            if (type == 1) {
64                // Type 1: query the maintenance station for the given station.
65                if (componentStations[root].count(station)) {
66                    // The station itself is online; answer with it.
67                    ans.push_back(station);
68                } else if (!componentStations[root].empty()) {
69                    // Otherwise return the smallest online station in the component.
70                    ans.push_back(*componentStations[root].begin());
71                } else {
72                    // No online station available in this component.
73                    ans.push_back(-1);
74                }
75            } else {
76                // Type 2: take the station offline by removing it from its component.
77                componentStations[root].erase(station);
78            }
79        }
80        return ans;
81    }
82};
83
1// Global union-find arrays.
2let parent: number[] = [];        // parent[i] points to the parent of node i
3let componentSize: number[] = []; // componentSize[root] holds the size of the component
4
5// Initialize the union-find structure with n elements (indices 0..n-1).
6function init(n: number): void {
7    parent = new Array(n);
8    componentSize = new Array(n).fill(1);
9    // Each element starts as its own root: parent[i] = i.
10    for (let i = 0; i < n; i++) {
11        parent[i] = i;
12    }
13}
14
15// Find the root representative of x with path compression.
16function find(x: number): number {
17    if (parent[x] !== x) {
18        parent[x] = find(parent[x]);
19    }
20    return parent[x];
21}
22
23// Merge the sets containing a and b.
24// Returns false if they already belong to the same set, true otherwise.
25function unite(a: number, b: number): boolean {
26    const rootA = find(a);
27    const rootB = find(b);
28    if (rootA === rootB) {
29        return false;
30    }
31    // Union by size: attach the smaller tree under the larger one.
32    if (componentSize[rootA] > componentSize[rootB]) {
33        parent[rootB] = rootA;
34        componentSize[rootA] += componentSize[rootB];
35    } else {
36        parent[rootA] = rootB;
37        componentSize[rootB] += componentSize[rootA];
38    }
39    return true;
40}
41
42// A simple binary min-heap of numbers, used to emulate C++'s ordered set
43// for quickly retrieving the smallest online station in a component.
44class MinHeap {
45    private data: number[] = [];
46
47    // Push a value into the heap, sifting it up to its correct position.
48    push(value: number): void {
49        this.data.push(value);
50        let i = this.data.length - 1;
51        while (i > 0) {
52            const parentIdx = (i - 1) >> 1;
53            if (this.data[parentIdx] <= this.data[i]) {
54                break;
55            }
56            [this.data[parentIdx], this.data[i]] = [this.data[i], this.data[parentIdx]];
57            i = parentIdx;
58        }
59    }
60
61    // Return the smallest value without removing it.
62    top(): number {
63        return this.data[0];
64    }
65
66    // Remove and return the smallest value, sifting the last element down.
67    pop(): number {
68        const top = this.data[0];
69        const last = this.data.pop()!;
70        if (this.data.length > 0) {
71            this.data[0] = last;
72            let i = 0;
73            const n = this.data.length;
74            while (true) {
75                const left = 2 * i + 1;
76                const right = 2 * i + 2;
77                let smallest = i;
78                if (left < n && this.data[left] < this.data[smallest]) {
79                    smallest = left;
80                }
81                if (right < n && this.data[right] < this.data[smallest]) {
82                    smallest = right;
83                }
84                if (smallest === i) {
85                    break;
86                }
87                [this.data[i], this.data[smallest]] = [this.data[smallest], this.data[i]];
88                i = smallest;
89            }
90        }
91        return top;
92    }
93
94    // Whether the heap currently holds no elements.
95    empty(): boolean {
96        return this.data.length === 0;
97    }
98}
99
100function processQueries(c: number, connections: number[][], queries: number[][]): number[] {
101    // Build the connected components from the given connections.
102    // Use indices 1..c, so allocate c + 1 slots.
103    init(c + 1);
104    for (const edge of connections) {
105        unite(edge[0], edge[1]);
106    }
107
108    // For each component root, store its online stations in a min-heap,
109    // so the smallest available station can be retrieved quickly.
110    const componentStations: MinHeap[] = new Array(c + 1);
111    for (let i = 0; i <= c; i++) {
112        componentStations[i] = new MinHeap();
113    }
114    // Track whether each station is currently online (not taken offline).
115    const online: boolean[] = new Array(c + 1).fill(true);
116
117    for (let i = 1; i <= c; i++) {
118        componentStations[find(i)].push(i);
119    }
120
121    const ans: number[] = [];
122    for (const query of queries) {
123        const type = query[0];
124        const station = query[1];
125        const root = find(station);
126        if (type === 1) {
127            // Type 1: query the maintenance station for the given station.
128            if (online[station]) {
129                // The station itself is online; answer with it.
130                ans.push(station);
131            } else {
132                // Otherwise return the smallest online station in the component,
133                // lazily discarding heap tops that are already offline.
134                const heap = componentStations[root];
135                while (!heap.empty() && !online[heap.top()]) {
136                    heap.pop();
137                }
138                if (!heap.empty()) {
139                    ans.push(heap.top());
140                } else {
141                    // No online station available in this component.
142                    ans.push(-1);
143                }
144            }
145        } else {
146            // Type 2: take the station offline by marking it offline.
147            online[station] = false;
148        }
149    }
150    return ans;
151}
152

Time and Space Complexity

  • Time Complexity: O((c + n + q) × log c), where c is the number of stations, and n and q are the number of connections and queries, respectively.

    • Building the Union-Find and processing all n connections via union takes O(n × α(c)), which is effectively O(n) (or bounded by O(n × log c)).
    • Distributing the c stations into the SortedList structures requires c insertions, each costing O(log c), giving O(c × log c).
    • Processing the q queries: each query performs a find, plus either a membership check / first-element access (in, st[root][0]) or a discard on a SortedList, each operation costing O(log c). This results in O(q × log c).
    • Combining these terms yields O((c + n + q) × log c).
  • Space Complexity: O(c), where c is the number of stations.

    • The Union-Find arrays p and size each use O(c) space.
    • The list of SortedList structures collectively stores all c stations, using O(c) space in total.
    • Therefore, the overall space complexity is O(c).

Pattern Learn more about how to find time and space complexity quickly.

Common Pitfalls

Pitfall 1: Using find(x) to Get the Root After the Stations Are Already Grouped, but Indexing the Sorted Set by the Wrong Root

A subtle and very common bug is mismatching the root used to populate the sorted sets with the root used to query them. Because union uses union-by-size, the final root of a component is not necessarily the smallest id, the first id, or any predictable value — it is whatever node ends up at the top of the tree.

If you build the sorted sets like this:

# WRONG: grouping by node id or a stale root
online_by_root[station].add(station)         # bug: uses the station itself, not its root

but later query with uf.find(station), the lookups will land on empty or incorrect sets and produce wrong answers (often -1 for grids that actually have online stations).

Solution: Always key the sorted sets by the canonical root returned by find, both when filling them and when querying them. The code does this correctly:

for station in range(1, c + 1):
    online_by_root[uf.find(station)].add(station)   # fill by root
...
root = uf.find(station)                             # query by the same root

Since find applies path compression, the root returned during the query phase is stable and consistent with the fill phase.


Pitfall 2: Forgetting That Path Compression Can Change parent, but Never the Root

Some implementations cache uf.find(station) once and reuse it across many queries, assuming the root might shift. With this Union-Find, all unions happen before any query, so each component's root is fixed for the entire query phase. The danger is the opposite: re-deriving the root incorrectly. As long as no union is called during the query loop (and none is here), uf.find(x) is guaranteed to return the same root every time, so caching is safe — but only because the structure is frozen.

Solution: Keep all union calls strictly in the preprocessing phase. If the problem were ever extended to add edges between queries, the precomputed online_by_root lists keyed by root would become invalid, and you'd need a different design (e.g., merging sorted sets on union, smaller-to-larger).


Pitfall 3: Off-by-One Errors With 1-Based Indexing

Stations are numbered 1..c, but the arrays are sized and looped over carelessly in many attempts:

uf = UnionFind(c)            # WRONG: index c is unreachable, station c overflows
online_by_root = [SortedList() for _ in range(c)]   # WRONG: too small

Because stations use ids up to c, you must allocate c + 1 slots and reserve index 0 as unused.

Solution: Size every structure as c + 1 and iterate range(1, c + 1), exactly as the code does. Index 0 is simply ignored.


Pitfall 4: Using a Plain List or Set Instead of a Sorted Structure

A natural but inefficient instinct is to store online stations in a plain Python set and compute the minimum with min(...) on each type-1 query:

ans.append(min(online_by_root[root]))   # O(m) per query — too slow

This turns each query into O(m), leading to O(q · c) overall, which times out on large inputs.

Solution: Use a SortedList (or TreeSet/std::set) so the minimum is online_by_root[root][0] in O(1) access (O(log m) for membership checks and deletions). This preserves the intended O((c + n + q) · log c) complexity.


Pitfall 5: Wrong Membership Test vs. Empty-Set Check Order

If you check "is the grid empty" before checking "is station x itself online," you can return the smallest online station even when x is online — which is correct only by coincidence (since x would also be in the set). The real bug appears when you forget to handle the x-online case at all and always return the minimum:

# WRONG: ignores that an online x must answer itself
if online_by_root[root]:
    ans.append(online_by_root[root][0])
else:
    ans.append(-1)

For a type-1 query on an online station x, the answer must be x itself, not the smallest online id in the grid.

Solution: Test station in online_by_root[root] first and return station; only fall back to the minimum (or -1) when x is offline:

if station in online_by_root[root]:
    ans.append(station)
elif online_by_root[root]:
    ans.append(online_by_root[root][0])
else:
    ans.append(-1)

Ready to land your dream job?

Unlock your dream job with a 5-minute quiz for a personalized study roadmap!

Get My Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

Which of these pictures shows the visit order of a depth-first search?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More