题目描述
在有向图中, 我们从某个节点和每个转向处开始, 沿着图的有向边走。 如果我们到达的节点是终点 (即它没有连出的有向边), 我们停止。
现在, 如果我们最后能走到终点,那么我们的起始节点是最终安全的。 更具体地说, 存在一个自然数 K, 无论选择从哪里开始行走, 我们走了不到 K 步后必能停止在一个终点。
哪些节点最终是安全的? 结果返回一个有序的数组。
该有向图有 N 个节点,标签为 0, 1, ..., N-1, 其中 N 是 graph 的节点数. 图以以下的形式给出: graph[i] 是节点 j 的一个列表,满足 (i, j) 是图的一条有向边。
示例: 输入:graph = [[1,2],[2,3],[5],[0],[5],[],[]] 输出:[2,4,5,6] 这里是上图的示意图。
解题思路
图拓扑排序
如果一个节点没有出度,那么这个节点自然就是安全节点,并且如果有其他节点链接到这个没有出度的节点,那么删除这个边后,若那个节点没有出度了,那么那个节点也是安全的。
这个题需要找出的节点是没有出度的节点(以及把这些节点去掉之后没有出度的节点),这样可以看出其实就是一个拓扑排序的过程。
知道是拓扑排序就很好理解了。只需要一个逆邻接表再维护一个出度表就行了。出度为0就出名该节点是最终的节点了,这就是寻找的安全节点,再根据逆邻接表找出哪些节点连接找这个节点,将这个节点的出度减一。如果又有节点的出度是0则说明该节点也是安全节点。
class Solution(object): def eventualSafeNodes(self, graph): """ :type graph: List[List[int]] :rtype: List[int] """ n = len(graph) visit = [False] * n out_degree = [0] * n reversed_table = [[] for _ in range(n)] for i in range(n): out_degree[i] = len(graph[i]) for item in graph[i]: reversed_table[item].append(i) queue = [] result = [] for i in range(n): if out_degree[i] == 0: queue.append(i) while queue: cur = queue.pop(0) visit[cur] = 1 for num in reversed_table[cur]: out_degree[num] -= 1 if out_degree[num] == 0: queue.append(num) for i in range(n): if visit[i] == 1: result.append(i) return result S = Solution() print(S.eventualSafeNodes([[1,2],[2,3],[5],[0],[5],[],[]]))