Does the One-Way Network Contain a Circuit
Solve this ProblemYou are given a network of one-way roads as an adjacency list of a directed graph. Decide whether it contains a circuit: a route that follows the roads and comes back to the node it started from (a road from a node to itself also counts).
In a directed graph, meeting an already visited node is not enough to prove a circuit; the important thing is whether that node is still on the current search path.
Test Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ n ≤ 10 nodes numbered 0 … n-1; graph[u] lists, in increasing order, every node v that has a one-way road u → v (adjacency-list form of a directed graph) - ◆
There are no repeated roads; a road from a node to itself is allowed and counts as a circuit - ◆
The graph may be disconnected - ◆
A circuit is a route that follows the one-way roads and returns to the node it started from; return true if the graph contains one
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Check Whether Each Node Can Return to Itself
BruteA circuit exists exactly when some node can reach itself by following at least one road. So for every node, run a full search starting from the nodes it points to and see whether the search comes back to that node. n searches, each visiting up to n nodes and E roads: O(n · (n + E)). It is correct but repeats a lot of work.
O(n · (n + E))O(n)1class Solution {
2 private boolean canReturn(int[][] graph, int start) {
3 boolean[] seen = new boolean[graph.length];
4 Deque<Integer> stack = new ArrayDeque<>();
5 for (int v : graph[start]) {
6 if (!seen[v]) {
7 seen[v] = true;
8 stack.push(v);
9 }
10 }
11 while (!stack.isEmpty()) {
12 int u = stack.pop();
13 if (u == start) return true;
14 for (int w : graph[u]) {
15 if (!seen[w]) {
16 seen[w] = true;
17 stack.push(w);
18 }
19 }
20 }
21 return false;
22 }
23
24 public boolean hasCircuit(int[][] graph) {
25 for (int start = 0; start < graph.length; start++) {
26 if (canReturn(graph, start)) return true;
27 }
28 return false;
29 }
30}Optimal — Depth-First Search With Three States
OptimalGive each node a state: 0 = not seen yet, 1 = on the current search path (being explored), 2 = completely finished. When exploring node u, look at each road u → v: if v is in state 1, we have found a road back to a node that is still on our current path, which is a circuit. If v is in state 0, explore it. When all roads of u are handled, mark u finished (2). Finished nodes need not be searched again, so every node and road is handled once: O(n + E).
O(n + E)O(n)1class Solution {
2 private boolean explore(int[][] graph, int node, int[] state) {
3 state[node] = 1;
4 for (int next : graph[node]) {
5 if (state[next] == 1) return true;
6 if (state[next] == 0 && explore(graph, next, state)) return true;
7 }
8 state[node] = 2;
9 return false;
10 }
11
12 public boolean hasCircuit(int[][] graph) {
13 int[] state = new int[graph.length];
14 for (int start = 0; start < graph.length; start++) {
15 if (state[start] == 0 && explore(graph, start, state)) return true;
16 }
17 return false;
18 }
19}