【LeetCode每日一题】——802.找到最终的安全状态

文章目录

  • 一【题目类别】
  • 二【题目难度】
  • 三【题目编号】
  • 四【题目描述】
  • 五【题目示例】
  • 六【题目提示】
  • 七【解题思路】
  • 八【时空频度】
  • 九【代码实现】
  • 十【提交结果】

一【题目类别】

二【题目难度】

  • 中等

三【题目编号】

四【题目描述】

  • 有一个有 n 个节点的有向,节点按 0n - 1 编号。由一个 索引从 0 开始 的 2D 整数数组 graph表示, graph[i]是与节点 i 相邻的节点的整数数组,这意味着从节点 igraph[i]中的每个节点都有一条边。
  • 如果一个节点没有连出的有向边,则该节点是 终端节点 。如果从该节点开始的所有可能路径都通向 终端节点 ,则该节点为 安全节点
  • 返回一个由中所有 安全节点 组成的数组作为答案。答案数组中的元素应当按 升序 排列。

五【题目示例】

  • 示例 1
    在这里插入<a class=图片描述" />

    • 输入: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 = = g r a p h . l e n g t h n == graph.length n==graph.length
  • 1 < = n < = 1 0 4 1 <= n <= 10^4 1<=n<=104
  • 0 < = g r a p h [ i ] . l e n g t h < = n 0 <= graph[i].length <= n 0<=graph[i].length<=n
  • 0 < = g r a p h [ i ] [ j ] < = n − 1 0 <= graph[i][j] <= n - 1 0<=graph[i][j]<=n1
  • g r a p h [ i ] graph[i] graph[i] 按严格递增顺序排列。
  • 中可能包含自环。
  • 中边的数目在范围 [ 1 , 4 ∗ 1 0 4 ] [1, 4 * 10^4] [1,4104] 内。

七【解题思路】

  • 利用拓扑排序的思想解决该问题
  • 我们首先构建一个反向,即假如之前i -> j,那么反向就变为j -> i,反向的目的是用来后续计算出度来找到终端节点
  • 同时构建原的出度数组,后续就会用该数组来找到安全节点
  • 然后将得到的所有终端节点都入队列,后续操作该队列即可得到所有终端节点
  • 然后将得到的安全节点(所有终端节点都是安全节点)保存到集合中
  • 然后通过逆向拓扑排序计算得到安全节点:
    • 首先从队列中取出一个安全节点
    • 然后查看它的邻接节点
      • 然后将邻接节点的出度减1
      • 如果此时出度为0,那么说明其为安全节点,将其入队列和集合中
  • 具体细节可以参考下面的代码
  • 最后返回结果即可

八【时空频度】

  • 时间复杂度: O ( m + n ) O(m + n) O(m+n) m m m的节点数, n n n的边数
  • 空间复杂度: O ( m + n ) O(m + n) O(m+n) m m m的节点数, n n n的边数

九【代码实现】

  1. Java语言版
class Solution {
    public List<Integer> eventualSafeNodes(int[][] graph) {
        // 中节点的个数
        int n = graph.length;
        // 用来存储反向
        List<List<Integer>> reverseGraph = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            reverseGraph.add(new ArrayList<>());
        }
        // 每个节点的出度
        int[] outDegree = new int[n];
        // 构建反向和出度数组
        for (int i = 0; i < n; i++) {
            outDegree[i] = graph[i].length;
            for (int neighbor : graph[i]) {
                reverseGraph.get(neighbor).add(i);
            }
        }
        // 初始化队列,将所有终端节点(出度为0的节点)加入队列
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            if (outDegree[i] == 0) {
                queue.offer(i);
            }
        }
        // 用集合存储安全节点
        Set<Integer> safeNodes = new HashSet<>(queue);
        // 逆向拓扑排序
        while (!queue.isEmpty()) {
            int node = queue.poll();
            for (int neighbor : reverseGraph.get(node)) {
                outDegree[neighbor]--;
                if (outDegree[neighbor] == 0) {
                    safeNodes.add(neighbor);
                    queue.offer(neighbor);
                }
            }
        }
        // 返回安全节点的升序列表
        List<Integer> res = new ArrayList<>(safeNodes);
        Collections.sort(res);
        return res;
    }
}
  1. Python语言版
class Solution:
    def eventualSafeNodes(self, graph: List[List[int]]) -> List[int]:
        # 中节点的个数
        n = len(graph)
        # 用来存储反向
        reverse_graph = defaultdict(list)
        # 每个节点的出度
        out_degree = [0] * n
        # 构建反向和出度数组
        for i, neighboors in enumerate(graph):
            out_degree[i] = len(neighboors)
            for neighboor in neighboors:
                reverse_graph[neighboor].append(i)
        # 初始化队列,将所有终端节点(出度为0的节点)加入队列
        queue = deque(i for i in range(n) if out_degree[i] == 0)
        # 用集合存储安全节点
        safe_nodes = set(queue)
        # 逆向拓扑排序
        while queue:
            node = queue.popleft()
            for neighboor in reverse_graph[node]:
                out_degree[neighboor] -= 1
                if out_degree[neighboor] == 0:
                    safe_nodes.add(neighboor)
                    queue.append(neighboor)
        # 返回安全节点的升序列表
        return sorted(safe_nodes)
  1. C++语言版
class Solution {
public:
    vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
        // 中节点的个数
        int n = graph.size();
        // 用来存储反向
        vector<vector<int>> reverseGraph(n);
        // 每个节点的出度
        vector<int> outDegree(n, 0);
        // 构建反向和出度数组
        for (int i = 0; i < n; i++) {
            outDegree[i] = graph[i].size();
            for (int neighbor : graph[i]) {
                reverseGraph[neighbor].push_back(i);
            }
        }
        // 初始化队列,将所有终端节点(出度为0的节点)加入队列
        queue<int> q;
        // 用集合存储安全节点
        unordered_set<int> safeNodes;
        for (int i = 0; i < n; i++) {
            if (outDegree[i] == 0) {
                q.push(i);
                safeNodes.insert(i);
            }
        }
        // 逆向拓扑排序
        while (!q.empty()) {
            int node = q.front();
            q.pop();
            for (int neighbor : reverseGraph[node]) {
                outDegree[neighbor]--;
                if (outDegree[neighbor] == 0) {
                    safeNodes.insert(neighbor);
                    q.push(neighbor);
                }
            }
        }
        // 返回安全节点的升序列表
        vector<int> res(safeNodes.begin(), safeNodes.end());
        sort(res.begin(), res.end());
        return res;
    }
};

十【提交结果】

  1. Java语言版
    在这里插入<a class=图片描述" />

  2. Python语言版
    在这里插入<a class=图片描述" />

  3. C++语言版
    在这里插入<a class=图片描述" />


http://www.niftyadmin.cn/n/5740736.html

相关文章

【八百客CRM-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

ThingsBoard规则链节点:Push to Edge节点详解

引言 1. Push to Edge 节点简介 2. 节点配置 2.1 基本配置示例 3. 使用场景 3.1 边缘计算 3.2 本地数据处理 3.3 实时响应 4. 实际项目中的应用 4.1 项目背景 4.2 项目需求 4.3 实现步骤 5. 总结 引言 ThingsBoard 是一个开源的物联网平台&#xff0c;提供了设备管…

FileLink如何帮助医疗行业实现安全且高效的跨网文件交换

在当今数字化时代&#xff0c;医疗行业在快速发展的同时&#xff0c;也面临着数据安全和信息流转效率的双重挑战。患者的健康记录、影像数据、检查报告等大量敏感信息需要在不同医院、诊所、实验室和保险公司之间高效、迅速地传递。然而&#xff0c;传统的邮件、传真和纸质文件…

软件工程3.0和软件工程2.0的区别

一、软件工程3.0和软件工程2.0的区别 软件工程3.0与软件工程2.0的主要区别体现在以下几个方面: 1. 技术基础和应用范围: - 软件工程2.0:在软件工程2.0阶段,软件工程逐渐从结构化编程转向面向对象编程,AI for SE(人工智能在软件工程中的应用)的应用范围和技术水平得到了…

从 HTTP 到 HTTPS 再到 HSTS:网站安全的演变与实践

近年来&#xff0c;随着域名劫持、信息泄漏等网络安全事件的频繁发生&#xff0c;网站安全变得越来越重要。这促使网络传输协议从 HTTP 发展到 HTTPS&#xff0c;再到 HSTS。本文将详细介绍这些协议的演变过程及其在实际应用中的重要性。 一、HTTP 协议 1.1 HTTP 简介 HTTP&…

Kubernetes架构及核心组件

一、基本架构 Kubernetes集群可以被看作是一个工厂,而各个组件则是这个工厂里的不同部门: Kubernetes API服务器:就像是这个工厂的总经理,负责接收所有的请求并将它们分配给相应的部门进行处理。 etcd:就像是这个工厂的记事本,负责记录所有的配置信息和状态信息,以便其…

springboot基于SpringBoot的旅游网站的设计与实现

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff0c;旅游网站当然也不能排除在外&#xff0c;随着旅游网站的不断成熟&#xff0c;它彻底改变了过去传统的旅游网站方式&#xff0c;不仅使旅游管理…

最新三维视觉下的扩散模型综述——Diffusion Models in 3D Vision: A Survey

目录 摘要 一、引言 二、扩散模型简介 A.扩散模型的介绍 B.扩散模型的数学基础 C.扩散模型的变体 D.三维视觉中的生成过程 三、三维视觉基础 A.三维表示 B.三维视觉中的深度学习方法 C.3D视觉中的挑战 四、三维扩散生成任务 A.无条件生成 B.图像到三维 C.文本到…