In a directed graph, we start at some node and every turn, walk along a directed edge of the graph. if we reach a node that is terminal (that is, it has no outgoing directed edges), we stop.
Now, say our starting node isEventually safeIf and only if we must eventually walk to a terminal node. More specifically, there exists a natural numberK
So that for any choice of where to walk, we must have stopped at a terminal node in lessK
Steps.
Which nodes are eventually safe? Return them as an array in sorted order.
The directed graph hasN
Nodes with labels0, 1, ..., N-1
, WhereN
Is the lengthgraph
. The graph is given in the following form:graph[i]
Is a list of labelsj
Such that(i, j)
Is a directed edge of the graph.
Example:Input: graph = [[1,2],[2,3],[5],[0],[5],[],[]]Output: [2,4,5,6]Here is a diagram of the above graph.
Note:
graph
Will have length at most10000
.
- The number of edges in the graph will not exceed
32000
.
- Each
graph[i]
Will be a sorted list of different integers, chosen within the range[0, graph.length - 1]
.
In a directed graph, if a node reaches the end point after many steps are taken from a node (the node with an outbound degree of 0 has no way to go), the node is considered as the final safe node. If it cannot be stopped, it is on a ring, that is, an insecure node. Stop in the natural K step to reach the security node, return the index value of all the security nodes that meet the requirements. The essence is to find nodes that are not on the loop in a directed graph.
Solution: DFS. nodes can be classified by dyeing. The value 0 indicates that the node has not been accessed. The value 1 indicates that the node has been accessed and found to be safe; 2 indicates that it has been accessed but found to be unsafe. We use the DFS method to traverse and return whether the node is safe: if it is found that it has been accessed, it will directly return whether it is a safe flag; otherwise, it will be marked as unsafe first, and then the DFS search will be performed (the node will be located in the DFS path at this time, so once the subsequent DFS arrives at this node, it is regarded as forming a ring, so false is returned directly ). When the entire DFS search is complete and the node is not found on the ring, it indicates that the node is safe, so mark it as safe. The space complexity is O (n), and the time complexity is O (n)
Solution 2: iterations record the degree of exit of each node. If the degree of exit is 0, it must be a node outside the loop, and then delete the vertex and the edge pointing to the vertex, continue to find the point with the outbound degree of 0
class Solution { public List<Integer> eventualSafeNodes(int[][] graph) { List<Integer> res = new ArrayList<>(); if(graph == null || graph.length == 0) return res; int nodeCount = graph.length; int[] color = new int[nodeCount]; for(int i = 0;i < nodeCount;i++){ if(dfs(graph, i, color)) res.add(i); } return res; } public boolean dfs(int[][] graph, int start, int[] color){ if(color[start] != 0) return color[start] == 1; color[start] = 2; for(int newNode : graph[start]){ if(!dfs(graph, newNode, color)) return false; } color[start] = 1; return true; }}
Python:
def eventualSafeNodes(self, graph): """ :type graph: List[List[int]] :rtype: List[int] """ n = len(graph) out_degree = collections.defaultdict(int) in_nodes = collections.defaultdict(list) queue = [] ret = [] for i in range(n): out_degree[i] = len(graph[i]) if out_degree[i]==0: queue.append(i) for j in graph[i]: in_nodes[j].append(i) while queue: term_node = queue.pop(0) ret.append(term_node) for in_node in in_nodes[term_node]: out_degree[in_node] -= 1 if out_degree[in_node]==0: queue.append(in_node) return sorted(ret)
Python:
# Time: O(|V| + |E|)# Space: O(|V|)import collectionsclass Solution(object): def eventualSafeNodes(self, graph): """ :type graph: List[List[int]] :rtype: List[int] """ WHITE, GRAY, BLACK = 0, 1, 2 def dfs(graph, node, lookup): if lookup[node] != WHITE: return lookup[node] == BLACK lookup[node] = GRAY for child in graph[node]: if lookup[child] == BLACK: continue if lookup[child] == GRAY or not dfs(graph, child, lookup): return False lookup[node] = BLACK return True lookup = collections.defaultdict(int) return filter(lambda node: dfs(graph, node, lookup), xrange(len(graph)))
Python:
Class solution (object): def eventualsafenodes (self, graph): "": Type graph: list [list [int]: Rtype: list [int] "if not graph: return [] n = Len (graph) # store the parent node D = {u: [] for u in range (n)} degree = [0] * n for u in range (n): For V in graph [u]: d [v]. append (u) degree [u] = Len (graph [u]) q = [U for u in range (N) if degree [u] = 0] res = [] While Q: node = Q. pop () res. append (node) for nodes in D [node]: Degree [nodes]-= 1 If degree [nodes] = 0: Q. append (nodes) return sorted (RES)
C ++:
class Solution {public: vector<int> eventualSafeNodes(vector<vector<int>>& graph) { vector<int> res; if (graph.size() == 0) { return res; } int size = graph.size(); vector<int> color(size, 0); // 0: not visited; 1: safe; 2: unsafe. for (int i = 0; i < size; ++i) { if (dfs(graph, i, color)) { // the i-th node is safe res.push_back(i); } } return res; }private: bool dfs(vector<vector<int>> &graph, int start, vector<int> &color) { if (color[start] != 0) { return color[start] == 1; } color[start] = 2; // mark it as unsafe because it is on the path for (int next : graph[start]) { if (!dfs(graph, next, color)) { return false; } } color[start] = 1; // mark it as safe because no loop is found return true; }};
[Leetcode] 802. Find eventual safe States find the final security status