在一个有向图中,我们从某个节点开始,每次沿着图的有向边走。 如果我们到达一个终端节点(也就是说,它没有指向外面的边),就停止。
现在,如果说我们的起始节点“最终是安全的”,当且仅当我们最终可以走到终端节点。 更具体地说,存在自然数K,对于任何行走的路线,我们必须在少于K步的情况下停在终端节点。
哪些节点是最终安全的? 返回它们升序排列的数组。
有向图具有N个节点,其标签为0, 1, ..., N-1,其中N是图的长度。 该图以下面的形式给出: graph[i]
是从i出发,通过边(i, j),所有能够到达的节点j组成的链表。
样例
样例1
输入: [[1,2],[2,3],[5],[0],[5],[],[]]
输出: [2,4,5,6]
样例2
输入: [[4,9],[3,5,7],[0,3,4,5,6,8],[7,8,9],[5,6,7,8],[6,7,8,9],[7,9],[8,9],[9],[]]
输出: [0,1,2,3,4,5,6,7,8,9]
分析
这道题给了我们一个有向图,然后定义了一种最终安全状态的结点,就是说该结点要在自然数K步内停止,所谓停止的意思,就是再没有向外的边,即没有出度,像上面例子中的结点5和6就是出度为0,因为graph[5]和graph[6]均为空。那么我们分析题目中的例子,除了没有出度的结点5和6之外,结点2和4也是安全状态结点,为啥呢,我们发现结点2和4都只能到达结点5,而结点5本身就是安全状态点,所以2和4也就是安全状态点了,所以我们可以得出的结论是,若某结点唯一能到达的结点是安全状态结点的话,那么该结点也同样是安全状态结点。那么我们就可以从没有出度的安全状态往回推,比如结点5,往回推可以到达结点4和2,先看结点4,此时我们先回推到结点4,然后将这条边断开,那么此时结点4出度为0,则标记结点4也为安全状态结点,同理,回推到结点2,断开边,此时结点2虽然入度仍为2,但是出度为0了,标记结点2也为安全状态结点
思路1、DFS
1、使用 dfs 遍历有向图的解法,经过分析某些结点不是安全状态,因为有环的存在,而环经过的所有结点,一定不是安全状态结点,所以我们可以通过DFS遍历有向图来找出环即可。在大多数的算法中,经典的DFS遍历法对于结点都有三种状态标记 UNKNOWN(0) SAFE(1) UNSAFE(-1),如果当前节点不是 UNKNOWN 的,表示改节点已经被访问过了,如果当前节点是 SAFE 返回 true 否则返回 false 。
2、然后开始遍历所有邻接结点,对该邻结点调用递归返回false了,说明当前结点是环结点,返回false。
思路2、BFS
1、遍历数组,使用 Map 记录每个节点的出度,只需先找到出度为 0 的数据存入 Queue
2、循环非空 Queue,取出队首元素,map包含改key,遍历 set 判断改节点是否存在,存在出度减 -1,存入 Queue
3、最后遍历数组indegree 如果出度为0 存入集合即可
public class Solution {
private static final int UNKNOWN = 0;
private static final int UNSAFE = -1;
private static final int SAFE = 1;
/**
* @param graph: a 2D integers array
* @return: return a list of integers
*/
public List<Integer> eventualSafeNodes(int[][] graph) {
// write your code here
int len = graph.length;
int[] states = new int[len];
List<Integer> result = new ArrayList<>();
for (int i = 0; i < len; i++) {
if (helper(i, graph, states)) {
result.add(i);
}
}
return result;
}
private boolean helper(int index, int[][] graph, int[] states) {
if (states[index] != UNKNOWN) {
return states[index] == SAFE;
}
states[index] = UNSAFE;
for (int node : graph[index]) {
if (!helper(node, graph, states)) {
return false;
}
}
states[index] = SAFE;
return true;
}
}
public class Solution {
/**
* @param graph: a 2D integers array
* @return: return a list of integers
*/
public List<Integer> eventualSafeNodes(int[][] graph) {
// write your code here
int len = graph.length;
int[] = new int[len];
Map<Integer, Set<Integer>> map = new HashMap<>();
Queue<Integer> queue = new LinkedList<>();
List<Integer> result = new ArrayList<>();
for (int i = 0; i < len; i++) {
int[] item = graph[i];
for (int edge : item) {
if (!map.containsKey(edge)) {
map.put(edge, new HashSet<>());
}
map.get(edge).add(i);
}
indegree[i] = item.length;
if (indegree[i] == 0) {
queue.offer(i);
}
}
while (!queue.isEmpty()) {
Integer node = queue.poll();
if (map.containsKey(node)) {
Set<Integer> set = map.get(node);
for (Integer i : set) {
indegree[i]--;
if (indegree[i] == 0) {
queue.offer(i);
}
}
}
}
for (int i = 0; i < len; i++) {
if (indegree[i] == 0) {
result.add(i);
}
}
Collections.sort(result);
return result;
}
}