本文涉及知识点
LeetCode802. 找到最终的安全状态
有一个有 n 个节点的有向图,节点按 0 到 n - 1 编号。图由一个 索引从 0 开始 的 2D 整数数组 graph表示, graph[i]是与节点 i 相邻的节点的整数数组,这意味着从节点 i 到 graph[i]中的每个节点都有一条边。
如果一个节点没有连出的有向边,则该节点是 终端节点 。如果从该节点开始的所有可能路径都通向 终端节点 ,则该节点为 安全节点 。
返回一个由图中所有 安全节点 组成的数组作为答案。答案数组中的元素应当按 升序 排列。
示例 1:
输入:graph = [[1,2],[2,3],[5],[0],[5],[],[]]
输出:[2,4,5,6]
解释:示意图如上。
节点 5 和节点 6 是终端节点,因为它们都没有出边。
从节点 2、4、5 和 6 开始的所有路径都指向节点 5 或 6 。
示例 2:
输入:graph = [[1,2,3,4],[1,2],[3,4],[0,4],[]]
输出:[4]
解释:
只有节点 4 是终端节点,从节点 4 开始的所有路径都通向节点 4 。
提示:
n == graph.length
1 <= n <= 104
0 <= graph[i].length <= n
0 <= graph[i][j] <= n - 1
graph[i] 按严格递增顺序排列。
图中可能包含自环。
图中边的数目在范围 [1, 4 * 104] 内。
C++BFS
本题本质是拓扑排序,如果有相应的模板,则用模板,否则用BFS。
预处理:graph记录的是后续的节点,计算vPre前续节点。
BFS的状态:leves[0]记录所有终端节点,leves[i]记录所有边都指向leves[0…i-1]的节点。空间复杂度:O(n)。
BFS的后续状态:cur所有前置节点中,扣掉指向leves[0…i-1]后,出度为0的节点。时间复杂度:O(m),m是边数。注意:不能有重边。
BFS的初始状态:所有终端节点。
BFS的返回值:用一维数组代替二维数组,并排序。
BFS的重复处理:数组出重。
代码
核心代码
class Solution {
public:
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
const int N = graph.size();
vector<vector<int>> vPre(N);
vector<int> vOut(N);
for (int i = 0; i < graph.size(); i++) {
for (const auto& next : graph[i]) {
vPre[next].emplace_back(i);
}
vOut[i] = graph[i].size();
}
vector<bool> vis(N);
vector<int> v;
auto Add = [&](int node) {
if (vis[node]) { return; }
if (0 != vOut[node]) { return; }
v.emplace_back(node);
vis[node] = true;
};
for (int i = 0; i < graph.size(); i++) {
if(graph[i].empty()){
Add(i);
}
}
for (int i = 0; i < v.size(); i++) {
for (const int ip : vPre[v[i]]) {
vOut[ip]--;
Add(ip);
}
}
sort(v.begin(), v.end());
return v;
}
};
单元测试
TEST_METHOD(TestMethod1)
{
graph = { {} };
auto res = Solution().eventualSafeNodes(graph);
AssertEx(vector<int>{0}, res);
}
TEST_METHOD(TestMethod2)
{
graph = { {0} };
auto res = Solution().eventualSafeNodes(graph);
AssertEx(vector<int>{}, res);
}
TEST_METHOD(TestMethod3)
{
graph = { {},{} };
auto res = Solution().eventualSafeNodes(graph);
AssertEx(vector<int>{0,1}, res);
}
TEST_METHOD(TestMethod4)
{
graph = { {1},{} };
auto res = Solution().eventualSafeNodes(graph);
AssertEx(vector<int>{0, 1}, res);
}
TEST_METHOD(TestMethod5)
{
graph = { {},{0} };
auto res = Solution().eventualSafeNodes(graph);
AssertEx(vector<int>{0, 1}, res);
}
TEST_METHOD(TestMethod6)
{
graph = { {1},{0} };
auto res = Solution().eventualSafeNodes(graph);
AssertEx(vector<int>{}, res);
}
TEST_METHOD(TestMethod11)
{
graph = { {1,2},{2,3},{5},{0},{5},{},{} };
auto res = Solution().eventualSafeNodes(graph);
AssertEx(vector<int>{2,4,5,6}, res);
}
TEST_METHOD(TestMethod12)
{
graph = { {1,2,3,4},{1,2},{3,4},{0,4},{} };
auto res = Solution().eventualSafeNodes(graph);
AssertEx(vector<int>{4}, res);
}
如果有不明白的,请加文末QQ群。如果要打包下载源码(CSDN下载频道偶尔审核不通过,原因未知),也请加QQ群。
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本**
算法用C++**实现。
!(https://img-blog.csdnimg.cn/f95ddae62a4e43a68295601c723f92fb.gif#pic_center)
最后
从时代发展的角度看,网络安全的知识是学不完的,而且以后要学的会更多,同学们要摆正心态,既然选择入门网络安全,就不能仅仅只是入门程度而已,能力越强机会才越多。
因为入门学习阶段知识点比较杂,所以我讲得比较笼统,大家如果有不懂的地方可以找我咨询,我保证知无不言言无不尽,需要相关资料也可以找我要,我的网盘里一大堆资料都在吃灰呢。
干货主要有:
①1000+CTF历届题库(主流和经典的应该都有了)
②CTF技术文档(最全中文版)
③项目源码(四五十个有趣且经典的练手项目及源码)
④ CTF大赛、web安全、渗透测试方面的视频(适合小白学习)
⑤ 网络安全学习路线图(告别不入流的学习)
⑥ CTF/渗透测试工具镜像文件大全
⑦ 2023密码学/隐身术/PWN技术手册大全
如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!
扫码领取
