Understanding the Problem
An eventual safe state in a directed graph is a node from which no cycle can be reached. In other words, if you start from this node and follow any path, you'll always end up at a terminal node (one with no outgoing edges) eventually.
Key Idea: Reverse Graph and Out-Degree Tracking
To detect such states efficiently, we reverse the graph. So instead of tracking which nodes we can go to, we look at who can reach us. We also maintain a count of outgoing edges (out-degree) for each node in the original graph.
Step-by-Step Logic
We start by collecting all terminal nodes (those with 0 out-degree) into a queue. These are trivially safe because there's nowhere to go from them.
Now, for each node we remove from the queue, we look at all nodes that point to it in the reversed graph. For each such node, we reduce their out-degree, as one of their outgoing edges now leads to a known safe node. If their out-degree reaches 0, they also become safe and are added to the queue.
Why This Works
If a node has an eventual path that leads to a cycle, its out-degree will never reach 0 — because at least one path keeps looping. Only nodes that can resolve all their paths into terminal nodes will have their out-degree reduced to zero eventually.
Examples
- Case with no cycles: Every node eventually leads to a terminal node, so all nodes are safe.
- Case with isolated cycle: Any node in or pointing to the cycle will never be safe.
- Edge case - empty graph: No nodes to process, so return an empty list.
Final Result
Once the process finishes, we collect all nodes whose out-degree is 0. These are the safe states. Sorting the result ensures a consistent output format.