【Leetcode】802. Find Eventual Safe States

题目地址:

https://leetcode.com/problems/find-eventual-safe-states/

给定一个有向图,如果从一个点出发走若干步后总会走到一个出度为 0 0 0的点,则称其为eventual safe。要求返回该图中所有的eventual safe的点。

题目的本质是要求把能走到某个环上的点都去掉不返回,而只返回那些走不到环上的点。一个点能否走到环上,当且仅当其邻居能否走到环上,这是一个递归的问题。我们可以对每个点进行染色, 0 0 0代表还没访问,可以进行访问;染 1 1 1代表本次DFS正在访问,染 2 2 2代表不能走到环上。同时我们让DFS返回是否发现了环,发现了环(表示当前顶点不是eventual safe的)则返回false,否则返回true。开始对每个点进行DFS,如果这个点之前已经染了色了,那说明之前DFS的时候已经判断好了其是否能走到环上,视情况加入最终结果即可;如果没染色(意思是标记为 0 0 0),那就对其进行访问,先将其标记为 1 1 1,然后开始访问其邻居,如果邻居为 2 2 2,说明该邻居走不到环上,略过;如果邻居为 1 1 1,说明产生了环,返回false;如果对邻居进行DFS发现了环,那也说明当前顶点不是eventual safe的,返回false。对其邻居全遍历完后如果都没有返回false,说明当前顶点是eventual safe的,则将其染为 2 2 2,同时返回true。只需要将所有染为 2 2 2的顶点加入最终结果即可,事实上,最后染为 1 1 1的点就是能走到环上的点。代码如下:

import java.util.ArrayList;
import java.util.List;

public class Solution {
    public List<Integer> eventualSafeNodes(int[][] graph) {
        List<Integer> res = new ArrayList<>();
        // 判空
        if (graph == null) {
            return res;
        }
        
        int[] color = new int[graph.length];
        
        for (int i = 0; i < graph.length; ++i) {
            if (dfs(i, color, graph)) {
                res.add(i);
            }
        }
        return res;
    }
    
    // 从node开始DFS,返回node是否是eventual safe的
    public boolean dfs(int node, int[] color, int[][] graph) {
    	// 如果之前访问过,就返回其是否eventual safe
        if (color[node] > 0) {
            return color[node] == 2;
        }
        
        // 标记其为正在访问
        color[node] = 1;
        
        // 开始递归遍历其邻居
        for (int next: graph[node]) {
        	// 如果已经知道next不会走到环了,就不必访问了,略过
            if (color[next] == 2) {
                continue;
            }
            
            // 如果next在当前DFS访问过,说明产生了环,返回false;
            // 如果next未访问过则对其进行访问,如果发现了环返回false
            if (color[next] == 1 || !dfs(next, color, graph)) {
                return false;
            }
        }
        
        // 如果之前都没发现环,则标记为2,返回true
        color[node] = 2;
        return true;
    }
}

时间复杂度 O ( V + E ) O(V+E) O(V+E),空间 O ( V ) O(V) O(V)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值