这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
题目
在有向图中,以某个节点为起始节点,从该点出发,每一步沿着图中的一条有向边行走。如果到达的节点是终点(即它没有连出的有向边),则停止。
对于一个起始节点,如果从该节点出发,无论每一步选择沿哪条有向边行走,最后必然在有限步内到达终点,则将该起始节点称作是 安全 的。
返回一个由图中所有安全的起始节点组成的数组作为答案。答案数组中的元素应当按 升序 排列。
该有向图有 n 个节点,按 0 到 n - 1 编号,其中 n 是 graph 的节点数。图以下述形式给出:graph[i] 是编号 j 节点的一个列表,满足 (i, j) 是图的一条有向边。
示例
输入: graph = [[1,2],[2,3],[5],[0],[5],[],[]]
输出: [2,4,5,6]
解释: 示意图如上。
输入: graph = [[1,2,3,4],[1,2],[3,4],[0,4],[]]
输出: [4]
提示
n == graph.length1 <= n <= 1040 <= graph[i].length <= ngraph[i] 按严格递增顺序排列图中可能包含自环图中边的数目在范围 [1, 4 * 104] 内
解题思路
根据题目所示,我们可以得到出度为0的节点以及所有最终走向出度为0节点的节点均为安全节点。
那么我们可以反推一下,从安全节点开始,遍历与之关联的节点,减少该节点的出度。
当该节点出度等于0时,加入结果集。
最后再按照题目要求进行升序排序。
代码实现
class Solution {
public List<Integer> eventualSafeNodes(int[][] graph) {
int n = graph.length;
List<List<Integer>> entrys = new ArrayList<>();
Queue<Integer> queue = new LinkedList<>();
int[] counts = new int[n];
// 初始化各节点关联节点
for(int i = 0; i < n; ++i){
entrys.add(new ArrayList<>());
}
for(int i = 0; i < n; ++i){
for(int g : graph[i]){
// 统计当前节点的出度
++counts[i];
// 将入度节点与出度节点进行关联
entrys.get(g).add(i);
}
}
// 得到安全节点
for(int i = 0; i < n; ++i){
if(counts[i] == 0){
queue.add(i);
}
}
List<Integer> ans = new ArrayList<>();
while(!queue.isEmpty()){
int idx = queue.poll();
// 将安全节点加入结果集
ans.add(idx);
// 遍历关联节点,减少该节点出度
for(int g : entrys.get(idx)){
if(--counts[g] == 0){
queue.add(g);
}
}
}
// 排序
Collections.sort(ans);
return ans;
}
}
复杂度分析
- 时间复杂度:O(n+m)。
- 空间复杂度:O(n+m)。
最后
文章有写的不好的地方,请大佬们不吝赐教,错误是最能让人成长的,愿我与大佬间的距离逐渐缩短!
如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!