In a directed graph, we start at some node and every turn, walk along a directed edge of the graph.  If we reach a node that is terminal (that is, it has no outgoing directed edges), we stop.

Now, say our starting node is eventually safe if and only if we must eventually walk to a terminal node.  More specifically, there exists a natural number K so that for any choice of where to walk, we must have stopped at a terminal node in less than K steps.

Which nodes are eventually safe?  Return them as an array in sorted order.

The directed graph has N nodes with labels 0, 1, ..., N-1, where N is the length of graph.  The graph is given in the following form: graph[i] is a list of labels j such that (i, j) is a directed edge of the graph.

Example:
Input: graph = [[1,2],[2,3],[5],[0],[5],[],[]]
Output: [2,4,5,6]
Here is a diagram of the above graph.

Note:

  • graph will have length at most 10000.
  • The number of edges in the graph will not exceed 32000.
  • Each graph[i] will be a sorted list of different integers, chosen within the range [0, graph.length - 1].

在一个有向图中,如果从一个节点出发走过很多步之后到达了终点(出度为0的节点,无路可走了),则认为这个节点是最终安全的节点。如果根本停不下来,那就是在一个环上,就是不安全节点。要在自然数K步内停止,到达安全节点,返回满足要求的排序好的所有安全节点的索引值。实质是在一个有向图中找出不在环路上的节点。

解法:DFS,可采用染色的方法对节点进行分类:0表示该结点还没有被访问;1表示已经被访问过了,并且发现是safe的;2表示被访问过了,但发现是unsafe的。我们采用DFS的方法进行遍历,并返回该结点是否是safe的:如果发现它已经被访问过了,则直接返回是否是safe的标记;否则就首先将其标记为unsafe的,然后进行DFS搜索(此时该结点会处在DFS的路径上,所以后面的DFS一旦到了该结点,就会被认为是形成了环,所以直接返回false)。当整个DFS的搜索都已经结束,并且都没有发现该结点处在环上时,说明该结点是safe的,所以此时将其最终标记为safe即可。空间复杂度是O(n),时间复杂度是O(n)

解法2: 迭代,记录下每个节点的出度,如果出度为0那必然是环路外的节点,然后将该点以及指向该点的边删除,继续寻找出度为0的点

class Solution {
public List<Integer> eventualSafeNodes(int[][] graph) {
List<Integer> res = new ArrayList<>();
if(graph == null || graph.length == 0) return res; int nodeCount = graph.length;
int[] color = new int[nodeCount]; for(int i = 0;i < nodeCount;i++){
if(dfs(graph, i, color)) res.add(i);
} return res;
}
public boolean dfs(int[][] graph, int start, int[] color){
if(color[start] != 0) return color[start] == 1; color[start] = 2;
for(int newNode : graph[start]){
if(!dfs(graph, newNode, color)) return false;
}
color[start] = 1; return true;
}
}

Python:

def eventualSafeNodes(self, graph):
"""
:type graph: List[List[int]]
:rtype: List[int]
"""
n = len(graph)
out_degree = collections.defaultdict(int)
in_nodes = collections.defaultdict(list)
queue = []
ret = []
for i in range(n):
out_degree[i] = len(graph[i])
if out_degree[i]==0:
queue.append(i)
for j in graph[i]:
in_nodes[j].append(i)
while queue:
term_node = queue.pop(0)
ret.append(term_node)
for in_node in in_nodes[term_node]:
out_degree[in_node] -= 1
if out_degree[in_node]==0:
queue.append(in_node)
return sorted(ret)

Python:

# Time:  O(|V| + |E|)
# Space: O(|V|)
import collections class Solution(object):
def eventualSafeNodes(self, graph):
"""
:type graph: List[List[int]]
:rtype: List[int]
"""
WHITE, GRAY, BLACK = 0, 1, 2 def dfs(graph, node, lookup):
if lookup[node] != WHITE:
return lookup[node] == BLACK
lookup[node] = GRAY
for child in graph[node]:
if lookup[child] == BLACK:
continue
if lookup[child] == GRAY or \
not dfs(graph, child, lookup):
return False
lookup[node] = BLACK
return True lookup = collections.defaultdict(int)
return filter(lambda node: dfs(graph, node, lookup), xrange(len(graph)))

Python:

class Solution(object):
def eventualSafeNodes(self, graph):
"""
:type graph: List[List[int]]
:rtype: List[int]
"""
if not graph: return [] n = len(graph)
# 用字段存储每个节点的父节点
d = {u:[] for u in range(n)}
degree = [0] * n
for u in range(n):
for v in graph[u]:
d[v].append(u)
degree[u] = len(graph[u]) Q = [u for u in range(n) if degree[u]==0]
res = []
while Q:
node = Q.pop()
res.append(node)
for nodes in d[node]:
degree[nodes] -= 1
if degree[nodes] == 0:
Q.append(nodes)
return sorted(res) 

C++:

class Solution {
public:
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
vector<int> res;
if (graph.size() == 0) {
return res;
}
int size = graph.size();
vector<int> color(size, 0); // 0: not visited; 1: safe; 2: unsafe.
for (int i = 0; i < size; ++i) {
if (dfs(graph, i, color)) { // the i-th node is safe
res.push_back(i);
}
}
return res;
}
private:
bool dfs(vector<vector<int>> &graph, int start, vector<int> &color) {
if (color[start] != 0) {
return color[start] == 1;
}
color[start] = 2; // mark it as unsafe because it is on the path
for (int next : graph[start]) {
if (!dfs(graph, next, color)) {
return false;
}
}
color[start] = 1; // mark it as safe because no loop is found
return true;
}
};

  

All LeetCode Questions List 题目汇总

[LeetCode] 802. Find Eventual Safe States 找到最终的安全状态的更多相关文章

  1. [LeetCode] Find Eventual Safe States 找到最终的安全状态

    In a directed graph, we start at some node and every turn, walk along a directed edge of the graph.  ...

  2. LeetCode 802. Find Eventual Safe States

    原题链接在这里:https://leetcode.com/problems/find-eventual-safe-states/ 题目: In a directed graph, we start a ...

  3. 【LeetCode】802. Find Eventual Safe States 解题报告(Python)

    [LeetCode]802. Find Eventual Safe States 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemi ...

  4. LC 802. Find Eventual Safe States

    In a directed graph, we start at some node and every turn, walk along a directed edge of the graph.  ...

  5. 【leetcode】802. Find Eventual Safe States

    题目如下: 解题思路:本题大多数人采用DFS的方法,这里我用的是另一种方法.我的思路是建立一次初始值为空的safe数组,然后遍历graph,找到graph[i]中所有元素都在safe中的元素,把i加入 ...

  6. 802. Find Eventual Safe States

    https://leetcode.com/problems/find-eventual-safe-states/description/ class Solution { public: vector ...

  7. Java实现 LeetCode 802 找到最终的安全状态 (DFS)

    802. 找到最终的安全状态 在有向图中, 我们从某个节点和每个转向处开始, 沿着图的有向边走. 如果我们到达的节点是终点 (即它没有连出的有向边), 我们停止. 现在, 如果我们最后能走到终点,那么 ...

  8. [Swift]LeetCode802. 找到最终的安全状态 | Find Eventual Safe States

    In a directed graph, we start at some node and every turn, walk along a directed edge of the graph.  ...

  9. LeetCode 277. Find the Celebrity (找到明星)$

    Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist o ...

随机推荐

  1. python开发应用-本地数据获取方法

    文件的打开.读写和关闭 文件的打开: file_obj=open(filename,mode='r',buffering=-1,...) filename是强制参数 mode是可选参数,默认值是r b ...

  2. MySQL 日期时间相关函数

    第一部分:时间差函数  timestampdiff.datediff.timediff 一.时间差函数:timestampdiff 语法:timestampdiff(interval, datetim ...

  3. 【Selenium-WebDriver实战篇】Java丨验证码图片去除干扰像素,方便验证码的识别(转)

    参考地址:https://www.cnblogs.com/haojieli/p/6212627.html 1.先来看看效果: 原图 除去干扰像素后 2.解析代码: 1).读取文件夹里面的图片 1 St ...

  4. Linux端口转发工具rinetd

    介绍:Rinetd是为在一个Unix和Linux操作系统中为重定向传输控制协议(TCP)连接的一个工具.Rinetd是单一过程的服务器,它处理任何数量的连接到在配置文件etc/rinetd中指定的地址 ...

  5. S1_搭建分布式OpenStack集群_06 nova服务配置 (控制节点)

    一.创建数据库(控制节点)创建数据库以及用户:# mysql -uroot -p12345678MariaDB [(none)]> CREATE DATABASE nova_api;MariaD ...

  6. WinDbg常用命令系列---日志操作相关命令log*

    .logopen (Open Log File) .logopen命令将事件和命令的副本从调试器命令窗口发送到新的日志文件. .logopen [Options] [FileName] .logope ...

  7. 认识Nodejs

    一.概念 ①JavaScript运行环境:Node.js不是一门语言,不是库也不是框架,是一个JavaScript运行环境,简单点来讲就是Node.js可以解析执行JavaScript代码,也就是说J ...

  8. c++ 题解

    43题 #include <random> #include <iostream> int main() { ][] = { {,,,}, {,,,}, {,,,}}; ; n ...

  9. c博客作业01--顺序分支结构

    0.展示PTA总分 1.本章学习总结 1.1 学习内容总结 1.运算符需注意的要点 '/'的左右两边如果均为整型数,其结果也为整型:'%'的左右两边只能为整型数: 优先级:逻辑运算符<关系运算符 ...

  10. GDOI2018 小学生图论题 [NTT]

    并没有传送门qwq 思路 首先要知道一个结论(或者说是一个套路):一个竞赛图缩点之后必定是一条链. 那么强联通分量的个数,就是这条链的边数+1. 考虑一条边什么时候会出现:当且仅当点集可以被分成\(S ...