LeetCode 802. 找到最终的安全状态 [java实现]

一、问题描述

有向图中,从起始节点出发,每一步沿图的一有向边。如果到达的节点是终点(即其没出的有向边),则停止。

若从起始节点出发,无论每一步选择沿哪条有向边行走,最后必在有限步到终点,则将该节点是 安全节点

返回图中所有安全节点组成的升序数组。

该有向图有 n 个节点,按 0n - 1 编号,其中 ngraph 的节点数。图以下述形式给出:graph[i] 是编号 j 节点的一个列表,满足 (i, j) 是图的一条有向边。

二、测试数据

示例 1:
输入:graph = [[1,2],[2,3],[5],[0],[5],[],[]]
输出:[2,4,5,6]
示例 2:
输入:graph = [[1,2,3,4],[1,2],[3,4],[0,4],[]]
输出:[4]
提示:
n == graph.length
1 <= n <= 104
0 <= graph[i].length <= n
graph[i] 按严格递增顺序排列。
图中可能包含自环。
图中边的数目在范围 [1, 4 * 10^4] 内。

三、解题思路

第一次采用暴力 dfs 破解( 超过时间限制 ):由于不成环的节点遍历最多为 n -1 次,深度到 n 确定成环不符合要求,若访问到 nums[x].length == 0,直接返回当前深度,已经遍历完毕,为安全节点。获取终点列表中的最大深度,大于或等于 n 则不符合要求。

​ 采用 深度优先遍历 + 三色标记法判断是否成环为解题关键

利用 int[] color = new int[length]; 创建节点访问关系数组

  • 白色(用 0 表示):未被访问的节点;
  • 灰色(用 1 表示):正在访问该节点,或者该节点在某个环上;
  • 黑色(用 2 表示):安全节点。

判断节点是否安全(是否成环):

  1. 初始化所有节点都为白色(未访问)。
  2. 依次遍历以 x 节点为起点的终点 y,采用 递归 形式深度优先遍历。
    • 若访问到灰色节点(在递归栈中的节点)则返回 false ,成环
    • 若访问到黑色节点(安全节点)直接返回 true ,以后都不会成环
  3. 访问时将 x 节点设置为灰色(表明正在访问)
  4. 访问结束后将 x 节点设置为黑色(安全节点)
//判断节点是否安全
	public boolean safe(int[][] graph,int[] color,int x){
        if(color[x]>0){
            return color[x]==2;
        }
        color[x] = 1;
        for(int y : graph[x]){
            if(!safe(graph,color,y)){
                return false;
            }
        }
        color[x] = 2;
        return true;
    }

四、java实现

class Solution {

    public List<Integer> eventualSafeNodes(int[][] graph) {
        int length = graph.length;

        //0--白--未被访问过 1--灰--位于递归栈中 2--黑--搜索完毕,安全结点
        int[] color = new int[length];

        List<Integer> list = new ArrayList<>();

        for(int i=0;i<length;i++){
            if(safe(graph,color,i)){
                list.add(i);
            }
        }
        return list;
    }

    public boolean safe(int[][] graph,int[] color,int x){
        if(color[x]>0){
            return color[x]==2;
        }
        color[x] = 1;
        for(int y : graph[x]){
            if(!safe(graph,color,y)){
                return false;
            }
        }
        color[x] = 2;
        return true;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值