[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. 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 most10000
.- 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]
.
这道题给了我们一个有向图,然后定义了一种最终安全状态的结点,就是说该结点要在自然数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也为安全状态结点。
分析到这里,思路应该比较明朗了,由于我们需要回推边,所以需要建立逆向边,用一个集合数组来存,由于题目要求返回的结点有序,我们可以利用集合TreeSet的自动排序的特性,由于需要断开边,为了不修改输入数据,所以我们干脆再建一个顺向边得了,即跟输入数据相同。还需要一个safe数组,布尔型的,来标记哪些结点是安全状态结点。在遍历结点的时候,直接先将出度为0的安全状态结点找出来,排入一个队列queue中,方便后续的处理。后续的处理就有些类似BFS的操作了,我们循环非空queue,取出队首元素,标记safe中该结点为安全状态结点,然后遍历其逆向边的结点,即可以到达当前队首结点的所有结点,我们在正向边集合中删除对应的边,如果此时结点出度为0了,将其加入队列queue中等待下一步处理,这样while循环退出后,所有的安全状态结点都已经标记好了,我们直接遍历safe数组,将其存入结果res中即可,参见代码如下:
解法一:
class Solution {
public:
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
vector<int> res;
int n = graph.size();
vector<bool> safe(n, false);
vector<set<int>> g(n, set<int>()), revg = g;
queue<int> q;
for (int i = ; i < n; ++i) {
if (graph[i].empty()) q.push(i);
for (int j : graph[i]) {
g[i].insert(j);
revg[j].insert(i);
}
}
while (!q.empty()) {
auto t = q.front(); q.pop();
safe[t] = true;
for (int i : revg[t]) {
g[i].erase(t);
if (g[i].empty()) q.push(i);
}
}
for (int i = ; i < n; ++i) {
if (safe[i]) res.push_back(i);
}
return res;
}
};
我们再来看一种DFS遍历有向图的解法。仔细分析题目中的例子,不难发现,之所以某些结点不是安全状态,因为有环的存在,而环经过的所有结点,一定不是安全状态结点,所以我们可以通过DFS遍历有向图来找出环即可。在大多数的算法中,经典的DFS遍历法对于结点都有三种状态标记,white,gray,和black,其中white表示结点还未遍历,gray表示正在遍历邻结点,black表示已经结束该结点的遍历。那么我们可以对每个结点都调用递归函数,在递归函数中,如果当前结点不是white,表示该结点已经访问过了,那么如果当前结点是black,直接返回true,如果是gray,直接返回false,因为遇到gray的结点,表示一定有环存在。否则我们给结点标记gray,然后开始遍历所有邻接结点,如果某个邻结点是black,直接跳过该结点。如果某个邻结点是gray,或者对该邻结点调用递归返回false了,说明当前结点是环结点,返回false。如果循环结束了,当前结点标记为black,并且返回true,参见代码如下:
解法二:
class Solution {
public:
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
int n = graph.size();
vector<int> res, color(n); // 0 white, 1 gray, 2 black
for (int i = ; i < n; ++i) {
if (helper(graph, i, color)) res.push_back(i);
}
return res;
}
bool helper(vector<vector<int>>& graph, int cur, vector<int>& color) {
if (color[cur] > ) return color[cur] == ;
color[cur] = ;
for (int i : graph[cur]) {
if (color[i] == ) continue;
if (color[i] == || !helper(graph, i, color)) {
return false;
}
}
color[cur] = ;
return true;
}
};
参考资料:
https://leetcode.com/problems/find-eventual-safe-states/solution/
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Find Eventual Safe States 找到最终的安全状态的更多相关文章
- [LeetCode] 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. ...
- 【LeetCode】802. Find Eventual Safe States 解题报告(Python)
[LeetCode]802. Find Eventual Safe States 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemi ...
- 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. ...
- Java实现 LeetCode 802 找到最终的安全状态 (DFS)
802. 找到最终的安全状态 在有向图中, 我们从某个节点和每个转向处开始, 沿着图的有向边走. 如果我们到达的节点是终点 (即它没有连出的有向边), 我们停止. 现在, 如果我们最后能走到终点,那么 ...
- [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. ...
- 【leetcode】802. Find Eventual Safe States
题目如下: 解题思路:本题大多数人采用DFS的方法,这里我用的是另一种方法.我的思路是建立一次初始值为空的safe数组,然后遍历graph,找到graph[i]中所有元素都在safe中的元素,把i加入 ...
- LeetCode 802. Find Eventual Safe States
原题链接在这里:https://leetcode.com/problems/find-eventual-safe-states/ 题目: In a directed graph, we start a ...
- 802. Find Eventual Safe States
https://leetcode.com/problems/find-eventual-safe-states/description/ class Solution { public: vector ...
- [LeetCode] Cracking the Safe 破解密码
There is a box protected by a password. The password is n digits, where each letter can be one of th ...
随机推荐
- windows下使用curl命令 && 常用curl命令
什么是curl命令? curl是利用URL语法在命令行方式下工作的开源文件传输工具.它被广泛应用在Unix.多种Linux发行版中,并且有DOS和Win32.Win64下的移植版本. 如何在windo ...
- metasploit 教程之信息收集
信息收集 信息收集范围很大,可以从不同层面,不同维度进行信息收集. 系统补丁 我们知道目标机器缺少什么补丁就意味着存在与其对应的漏洞.我们可以利用这些漏洞来达到我们渗透攻击的目的. # 使用的模块 u ...
- 转:spring boot log4j2配置(使用log4j2.yml文件)---YAML 语言教程
转:spring boot log4j2配置(使用log4j2.yml文件) - CSDN博客http://blog.csdn.net/ClementAD/article/details/514988 ...
- Python 概念小屋
 Python 中的 if __name__ == '__main__' 该如何理解 python多进程的理解 multiprocessing Process join run
- FTP:mget匹配文件名后下载
需求:从FTP某目录取每日构建的apk下载到本地 难点:文件名中有构建时间,而这个时间不算固定值,因此文件名不固定 解决方案:mget匹配文件名后下载 BAT版本: :: Filename:Proje ...
- WSL用xshell连接
编辑配置文件 sudo vim /etc/ssh/sshd_config Port 8022(因为 Windows 10 的 SSH 端口已经默认被占用,所以我换成了一个新的端口) (去掉前面的 #) ...
- AWK如何打印从某一列到最后一列的内容
awk -F " " '{for (i=4;i<=NF;i++)printf("%s ", $i);print ""}' file
- MySQL的常见存储引擎介绍与参数设置调优(转载)
原文地址:http://www.cnblogs.com/demon89/p/8490229.html MySQL常用存储引擎之MyISAM 特性: 1.并发性与锁级别 2.表损坏修复 check ta ...
- 【python】命令行神器 Click 简明笔记
全文拷贝自 命令行神器 Click 简明笔记 Click Click 是用 Python 写的一个第三方模块,用于快速创建命令行.我们知道,Python 内置了一个 Argparse 的标准库用于创建 ...
- python3 基础语法(一)
一.标识符: 第一个字符必须是字母表中字母或下划线 “_” . 例如: #!/usr/bin/env python #coding=utf-8 a = 3 _aa = 3 a3 = 3 _aa3 = ...