Problem
There is a directed graph of n
nodes with each node labeled from 0
to n - 1
. The graph is represented by a 0-indexed 2D integer array graph
where graph[i]
is an integer array of nodes adjacent to node i
, meaning there is an edge from node i
to each node in graph[i]
.
A node is a terminal node if there are no outgoing edges. A node is a safe node if every possible path starting from that node leads to a terminal node.
Return an array containing all the safe nodes of the graph. The answer should be sorted in ascending order.
Examples
Example 1:
graph LR; 0 --> 1 & 2 1 --> 2 & 3 2 --> 5 3 --> 0 4 --> 5 6
Here is another view of same graph:
|
|
Example 2:
|
|
So, basically method signature:
|
|
Solution
Lets look at example 1. We can see in the graph, that 0 is not a safe node, as that leads to circle. We can go from 0
to 2
, and that will eventually lead us to terminal node, but that is just 1 possibility. Likewise, 1
is also not a safe node, as it is part of cycle with node 0
. So, basically we need to be careful, not to get in the cycle.
Method 1 - DFS
We are already given adjacency list representation of graph. Lets identify a few nodes:
- Terminal Nodes: Nodes with no outgoing edges are terminal nodes and hence safe.
- Safe Nodes: A node is considered safe if all possible paths starting from that node only lead to terminal nodes (or other safe nodes).
To identify safe nodes, we can use Depth-First Search (DFS) and track the state of each node:
- State 0: Node has not been visited.
- State 1: Node is being visited but not verified as safe (part of the current DFS path).
- State 2: Node is fully processed and is a safe node.
For every node, follow these checks:
- If the node is already visited or confirmed to be safe, return its state.
- If the node has no outgoing edges, mark it as safe by setting its state to 2.
- For an unvisited node, process each of its outgoing edges by:
- Recursively running the function on the adjacent nodes.
- If any adjacent node returns a state of 1 (indicating a cycle), mark the current node as unsafe and return false.
- If, after processing all adjacent nodes, no cycles are detected, mark the current node as safe by setting its state to 2.
Finally, return the state of the node.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(V + E)
whereV
is the number of nodes andE
is the number of edges. Each node and edge is processed a constant number of times. - 🧺 Space complexity:
O(V)
for the recursion stack and the state array used to track the state of each node.