We need all cities to reach city 0, so we traverse outward from city 0 and check edge directions. Build an undirected neighbors graph for traversal, but store original edges in edges set to check direction. When moving from city A to neighbor B, if the original edge goes from A to B (away from 0), it needs to be reversed. dfs ensures we visit every city exactly once.
edges as (a, b) pairs.neighbors treating edges as undirected.dfs from city 0, marking visited cities in visit set.neighbor:(neighbor, city) exists in the edges set.changes.neighbor.class Solution:
def minReorder(self, n: int, connections: List[List[int]]) -> int:
edges = {(a, b) for a, b in connections}
neighbors = {city: [] for city in range(n)}
visit = set()
changes = 0
for a, b in connections:
neighbors[a].append(b)
neighbors[b].append(a)
def dfs(city):
nonlocal changes
visit.add(city)
for neighbor in neighbors[city]:
if neighbor in visit:
continue
if (neighbor, city) not in edges:
changes += 1
dfs(neighbor)
dfs(0)
return changesInstead of using a separate set to track edge directions, we can encode direction information directly in the adjacency list. When adding edges, we store the original direction as a positive value and the reverse as negative. During dfs, positive nei values indicate edges pointing away from city 0, which need reversal.
adj where each edge (u, v) adds v to adj[u] and -u to adj[v].dfs from city 0 with parent = -1.nei (neighbor):abs(nei) equals the parent (to avoid going back).nei > 0 (edge needs reversal).abs(nei) as the next node.class Solution:
def minReorder(self, n: int, connections: List[List[int]]) -> int:
adj = [[] for _ in range(n)]
for u, v in connections:
adj[u].append(v)
adj[v].append(-u)
def dfs(node, parent):
changes = 0
for nei in adj[node]:
if abs(nei) == parent:
continue
changes += dfs(abs(nei), node) + (nei > 0)
return changes
return dfs(0, -1)bfs works equally well since we just need to visit all nodes once from city 0. We store each edge with a flag isForward indicating if it is a forward edge (pointing away from city 0). Processing level by level in queue, whenever we traverse a forward edge, we count it as needing reversal.
adj where each edge (u, v) stores (v, 1) in adj[u] and (u, 0) in adj[v].queue with city 0 and mark it visited in visit array.queue is not empty:node.neighbor, mark it visited, add isForward to the count, and enqueue it.class Solution:
def minReorder(self, n: int, connections: List[List[int]]) -> int:
adj = [[] for _ in range(n)]
for u, v in connections:
adj[u].append((v, 1))
adj[v].append((u, 0))
visit = [False] * n
queue = deque([0])
visit[0] = True
changes = 0
while queue:
node = queue.popleft()
for neighbor, isForward in adj[node]:
if not visit[neighbor]:
visit[neighbor] = True
changes += isForward
queue.append(neighbor)
return changesA common mistake is building only a directed adjacency list based on the given edges. Since we need to traverse the entire tree starting from city 0, we must treat edges as undirected for traversal purposes while separately tracking the original direction to count reversals.
When checking if an edge needs reversal, it is easy to get the condition backwards. Remember that edges pointing away from city 0 need reversal. If traversing from node A to neighbor B and the original edge is (A, B), it points away from 0 and must be counted; if the original edge is (B, A), it already points toward 0.
In the DFS-II approach that uses negative values to encode direction, node 0 cannot be represented as negative since -0 == 0. This edge case must be handled by using the parent check (abs(nei) == parent) rather than relying solely on sign for all nodes.