leetcode-802:找到最终的安全状态

简介: leetcode-802:找到最终的安全状态

题目

题目链接

在有向图中,以某个节点为起始节点,从该点出发,每一步沿着图中的一条有向边行走。如果到达的节点是终点(即它没有连出的有向边),则停止。

对于一个起始节点,如果从该节点出发,无论每一步选择沿哪条有向边行走,最后必然在有限步内到达终点,则将该起始节点称作是 安全 的。

返回一个由图中所有安全的起始节点组成的数组作为答案。答案数组中的元素应当按 升序 排列。

该有向图有 n 个节点,按 0 到 n - 1 编号,其中 n 是 graph 的节点数。图以下述形式给出: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]

解题

方法一:拓扑排序

参考链接

若一个节点的出边相连的点都是安全的,则该点也是安全的,在反向图中,inDeg就是记录出边数量,每次从安全点遍历到该点,都会使得inDeg-1,当inDeg==0,代表每个节点出边相连的点都是安全的。

graph[x].size()是正向图的出度,也就是反向图的入度

class Solution {
public:
    vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
        int n=graph.size();
        //获得反向图和每个顶点的入度
        vector<vector<int>> rg(n);//reversed graph
        vector<int> inDeg(n);
        for(int x=0;x<n;x++){
            for(int y:graph[x]){
                rg[y].push_back(x);
            }
            inDeg[x]=graph[x].size();//反向图的入度是正向图的出度
        }
        //初始化(将 入度为0的顶点,加入队列)
        queue<int> q;
        for(int i=0;i<n;i++){
            if(inDeg[i]==0) q.push(i);
        }
        //将入度为0的顶点的相邻边删去,相邻顶点入度-1,如果入度为0,加入到队列中
        while(!q.empty()){
            int y=q.front();
            q.pop();
            for(int x:rg[y]){
                if(--inDeg[x]==0){
                    q.push(x);
                }
            }
        }
        //入度为0的顶点 即为安全点 
        vector<int> res;
        for(int i=0;i<n;i++){
            if(inDeg[i]==0) res.push_back(i);
        }
        return res;
    }
};

方法二:深度优先搜索 + 三色标记法

解答

由于color[x]=1后面遍历每个出边,如果出边对应顶点都是安全点,那么color[x]=2,如果不安全则为color[x]=1

因此当再次遍历到的时候,访问过的话color[x]>0。出边的顶点是不安全的,那么该顶点一定是不安全的,出边的顶点是安全的,那么该顶点是安全的。

写法一

由于用到多次传参,比如graph和color,可以使用function包装lambda表达式,减少代码量

class Solution {
public:
    vector<int> eventualSafeNodes(vector<vector<int>> &graph) {
        int n = graph.size();
        vector<int> color(n);
        function<bool(int)> safe = [&](int x) {
            if (color[x] > 0) {
                return color[x] == 2;//如果该顶点是安全点,就返回true
            }
            color[x] = 1;
            for (int y : graph[x]) {//任意的出边都要是安全点才行,否则该顶点就不是安全顶点
                if (!safe(y)) {
                    return false;
                }
            }
            color[x] = 2;//任意出边都是安全点,因此该顶点是安全点
            return true;
        };
        vector<int> ans;
        for (int i = 0; i < n; ++i) {
            if (safe(i)) {
                ans.push_back(i);
            }
        }
        return ans;
    }
};

补充

lambda表达式相关链接

function在这当作lambda表达式的装饰器,统一成function类型,方便管理和使用,function 中bool为返回值,int为形参

写法二

class Solution {
public:
    bool safe(int x,vector<vector<int>>& graph,vector<int>& color){
        if(color[x]>0){
            return color[x]==2;
        }
        color[x]=1;
        for(int y:graph[x]){
            if(!safe(y,graph,color)) return false;
        }
        color[x]=2;
        return true;
    }
    vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
        int n=graph.size();
        vector<int> color(n);
        vector<int> res;
        for(int i=0;i<n;i++){
            if(safe(i,graph,color)) res.push_back(i);
        }
        return res;
    }
};


相关文章
|
20天前
|
机器学习/深度学习 人工智能 自然语言处理
从原理出发 - 提示词如何影响大模型的输出
在探索人工智能的深海中,提示词(Prompt)是引导大模型输出的灯塔。本文希望通过对自身所学所思进行总结,解析提示词如何塑造AI的响应,揭示其背后的机制。
|
6月前
|
JSON 前端开发 Java
前后端数据交互-----表单数据获取不到,出错的原因,在编写接口时,没有考虑数据如何返回,解决问题的思路,找到自己出错的地方,围绕着出错的地方进行考虑(很重要),找对解决问题的视频,理清返回数据的思路
前后端数据交互-----表单数据获取不到,出错的原因,在编写接口时,没有考虑数据如何返回,解决问题的思路,找到自己出错的地方,围绕着出错的地方进行考虑(很重要),找对解决问题的视频,理清返回数据的思路
LeetCode-1606 找到处理请求最多的服务器
LeetCode-1606 找到处理请求最多的服务器
|
8月前
leetcode-6134:找到离给定两个节点最近的节点
leetcode-6134:找到离给定两个节点最近的节点
55 0
|
存储 算法 Java
算法打卡Day5_lecode_448. 找到所有数组中消失的数字
算法打卡Day5_lecode_448. 找到所有数组中消失的数字
算法打卡Day5_lecode_448. 找到所有数组中消失的数字
|
人工智能
LeetCode 1389. 按既定顺序创建目标数组
给你一个字符串 s,它由数字('0' - '9')和 '#' 组成。我们希望按下述规则将 s 映射为一些小写英文字符
94 0
|
Web App开发 Windows
当UI走查说页面色值错误时,先别急着检查代码
颜色一直是UI设计师们非常敏感的问题,为何屏幕会出现色差?工作中如何避免?
找到所有数组中消失的数字(算法题)
找到所有数组中消失的数字(算法题)