802. Find Eventual Safe States
Question
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 (or another safe node).
Return an array containing all the safe nodes of the graph. The answer should be sorted in ascending order.
Example 1:

Input: graph = [[1,2],[2,3],[5],[0],[5],[],[|1,2],[2,3],[5],[0],[5],[],[]]
Output: [2,4,5,6]
Explanation: The given graph is shown above.
Nodes 5 and 6 are terminal nodes as there are no outgoing edges from either of them.
Every path starting at nodes 2, 4, 5, and 6 all lead to either node 5 or 6.
Example 2:
Input: graph = [[1,2,3,4],[1,2],[3,4],[0,4],[|1,2,3,4],[1,2],[3,4],[0,4],[]]
Output: [4]
Explanation:
Only node 4 is a terminal node, and every path starting at node 4 leads to node 4.
Constraints:
n == graph.length1 <= n <= 1040 <= graph[i].length <= n0 <= graph[i][j] <= n - 1graph[i]is sorted in a strictly increasing order.- The graph may contain self-loops.
- The number of edges in the graph will be in the range
[1, 4 * 104].
Approach 1: DFS
Intuition
- Cycle detection
Algorithm
- Declare & initialize 3 arrays
visited,pathVisited,safeStateswith sizen& value0 - Loop through the
graphand if the node is not visited calldfsfor that node - Declare
vector<int> ans - Iterate through
safeStatesvector- If
safeStatesfor a node is equal to 1- Push that node into the
ansvector
- Push that node into the
- If
- Return
ans
- DFS
- Base Case
- If visited & path visited
- Set not a safe state (as cycle detected)
- Return true
- If visited & not pathVisited
- Set as a safe state (as cycle not detected)
- Return false
- If visited & path visited
- Processing
- Set visited
- Set pathVisited
- Recurse Case
- Iterate through the neighbors of the node in the graph
- Call dfs for each neighbor, if it returns true
- Set safeStates for the Current Node = 0
- Return true
- Back tracking
- Set safeStates for the Current Node = 1
- Reset pathVisited for the node
- Return false;
- Base Case
Code
class Solution {
public:
bool dfs(int node, vector<vector<int>>& graph, vector<int>& visited,
vector<int>& pathVisited, vector<int>& safeStates) {
// base case
if (visited[node] && pathVisited[node]) {
safeStates[node] = 0;
return true;
}
if (visited[node] && !pathVisited[node]) {
safeStates[node] = 1;
return false;
}
// processing
visited[node] = 1;
pathVisited[node] = 1;
// recurse case
for (auto neighbor : graph[node]) {
if (dfs(neighbor, graph, visited, pathVisited, safeStates)) {
safeStates[node] = 0;
return true;
}
}
// backtracking
safeStates[node] = 1;
pathVisited[node] = 0;
return false;
}
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
int n = graph.size();
vector<int> visited(n, 0);
vector<int> pathVisited(n, 0);
vector<int> safeStates(n, 0);
for (int i = 0; i < n; i++) {
if (!visited[i]) {
dfs(i, graph, visited, pathVisited, safeStates);
}
}
vector<int> ans;
for (int i = 0; i < n; i++) {
if (safeStates[i] == 1) {
ans.push_back(i);
}
}
return ans;
}
};
Complexity Analysis
- Time Complexity:
- Space Complexity:
Approach 2: BFS (Kahn's Algorithm)
Intuition
- TOPO sort
- Kahn's Algorithm
Algorithm
- Initialize variables:
n = number of nodes in the graphrevGraph: a new graph to store the reversed edgesindegree: an array to count incoming edges in the reversed graphqueue: for BFS traversal of safe nodessafeStates: a list to store the final answer
- Build the reversed graph:
- For each edge
i → neighboringraph:- Add an edge
neighbor → iinrevGraph
- Add an edge
- For each edge
- Compute indegrees in the reversed graph:
- For every node
i, iterate overrevGraph[i]:- Increment
indegree[neighbor]++
- Increment
- For every node
- Push nodes with 0 indegree into the queue:
- These nodes have no outgoing edges in the original graph, so they are safe
- Run BFS (Kahn’s Algorithm):
- While
queueis not empty:- Pop a node
node - Add
nodetosafeStates - For each
neighborinrevGraph[node]:- Decrease
indegree[neighbor]-- - If
indegree[neighbor] == 0, pushneighborinto the queue
- Decrease
- Pop a node
- While
- Sort
safeStates(optional depending on output requirement) - **Return
safeStates
Code
class Solution {
public:
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
int n = graph.size();
vector<vector<int>> revGraph(n, vector<int>());
for (int i = 0 ; i < n ; i++) {
for (auto neighbor: graph[i]) {
revGraph[neighbor].push_back(i);
}
}
vector<int> indegree(n, 0);
for (int i = 0 ; i < n ; i++) {
for (int neighbor: revGraph[i]) {
indegree[neighbor]++;
}
}
queue<int> q;
for (int i = 0 ; i < n ; i++) {
if (indegree[i] == 0) {
q.push(i);
}
}
vector<int> safeStates;
while (!q.empty()) {
int node = q.front();
q.pop();
safeStates.push_back(node);
for (int neighbor: revGraph[node]) {
indegree[neighbor]--;
if (indegree[neighbor] == 0 ) {
q.push(neighbor);
}
}
}
sort(safeStates.begin(), safeStates.end());
return safeStates;
}
};
Complexity Analysis
- Time Complexity:
- Space Complexity: