Graphs - DFS · Medium
LeetCode 1466: Reorder Routes to Make All Paths Lead to the City Zero — solution
Solve LeetCode 1466 by traversing the road network from city 0 as if it were undirected, counting every road that points away from 0 — O(n) time, O(n) space.
Problem in plain words
There are n cities and exactly n - 1 one-way roads, and if you ignore directions the roads form a tree (every city is connected, no cycles). Each road [a, b] lets you drive from a to b only. Find the smallest number of roads whose direction you must flip so that every city can drive to city 0.
Example: n = 4, roads 0 → 1, 2 → 1, 3 → 0. The road 0 → 1 points away from 0 and must be flipped. Then 2 → 1 → 0 and 3 → 0 already work, so the answer is 1.
Intuition
Because the underlying graph is a tree, there is exactly one path between city 0 and any other city. Explore outward from city 0. Every time you cross a road in its original direction you are moving away from 0, which means cars on that road would drive away from the capital — it must be flipped. Crossing a road against its direction means it already points toward 0. So store each road twice: the original direction with cost 1 and the reverse with cost 0, then add up the costs of the edges used by a BFS from 0.
Approach
- Build an adjacency list. For each road
[a, b], add(b, 1)toa's list and(a, 0)tob's list. - BFS (or DFS) from city 0 with a visited array.
- When you move from
cityto an unvisited neighbour through an edge with costc, addcto the answer. - Return the total once all cities are visited.
Dry run
Roads 0 → 1, 2 → 1, 3 → 0.
| From | To | Original road | Cost | Flips so far |
|---|---|---|---|---|
| 0 | 1 | 0 → 1 (away from 0) | 1 | 1 |
| 0 | 3 | 3 → 0 (toward 0) | 0 | 1 |
| 1 | 2 | 2 → 1 (toward 0) | 0 | 1 |
Java solution
class Solution {
public int minReorder(int n, int[][] connections) {
List<List<int[]>> graph = new ArrayList<>();
for (int i = 0; i < n; i++) {
graph.add(new ArrayList<>());
}
for (int[] road : connections) {
graph.get(road[0]).add(new int[] {road[1], 1}); // original direction
graph.get(road[1]).add(new int[] {road[0], 0}); // reverse, already fine
}
boolean[] visited = new boolean[n];
Deque<Integer> queue = new ArrayDeque<>();
visited[0] = true;
queue.offer(0);
int flips = 0;
while (!queue.isEmpty()) {
int city = queue.poll();
for (int[] edge : graph.get(city)) {
int next = edge[0];
if (!visited[next]) {
visited[next] = true;
flips += edge[1];
queue.offer(next);
}
}
}
return flips;
}
}Python solution
class Solution:
def minReorder(self, n: int, connections: List[List[int]]) -> int:
graph = [[] for _ in range(n)]
for a, b in connections:
graph[a].append((b, 1)) # original direction: needs a flip
graph[b].append((a, 0)) # reverse direction: already points to 0
visited = [False] * n
visited[0] = True
queue = deque([0])
flips = 0
while queue:
city = queue.popleft()
for nxt, cost in graph[city]:
if not visited[nxt]:
visited[nxt] = True
flips += cost
queue.append(nxt)
return flipsComplexity
| Measure | Cost | Why |
|---|---|---|
| Time | O(n) | There are n − 1 roads, stored twice, and each is examined once. |
| Space | O(n) | Adjacency list, visited array and queue are all linear. |
Edge cases and common mistakes
- Only storing original directions — then you cannot reach cities whose roads point toward 0. Store both directions with different costs.
- Swapping the costs — moving outward along an original edge is what needs flipping, so the original direction carries cost
1. - Recursion depth — with up to 5·10^4 cities in a line, recursive DFS can overflow; BFS or an explicit stack is safer.
›Why is the greedy count minimal?
In a tree each city has a unique path to 0, so each road's required direction is forced. Every road pointing away from 0 must be flipped, and no other flip helps — the count is exact.
