想要精通算法和SQL的成长之路 - 找到最终的安全状态

想要精通算法和SQL的成长之路 - 找到最终的安全状态

  • 前言
  • [一. 找到最终的安全状态](#一. 找到最终的安全状态)
    • [1.1 初始化邻接图](#1.1 初始化邻接图)
    • [1.2 构建反向邻接图](#1.2 构建反向邻接图)
    • [1.3 BFS遍历](#1.3 BFS遍历)
    • [1.4 完整代码](#1.4 完整代码)

前言

想要精通算法和SQL的成长之路 - 系列导航

一. 找到最终的安全状态

原题链接

我们从题目中可以看出来:

  • 出度为0的,就是终端节点。
  • 如果存在路径通向终端节点,那么该节点就是安全节点。那么终端节点本身也可以作为安全节点。
  • 而题目要求我们返回的是安全节点。
  • 满足题目要求的节点,一定是和终端节点相连的节点。

思路如下:

  1. 我们构建有向邻接图,并且统计出度。
  2. 出度为0的丢到队列中。
  3. 每层循环,处理出度为0的节点(终端节点),我们反向拿到它的前置节点(因此构建邻接图的时候要反向构建有向邻接图), 更新它的出度。若前置节点的出度为0,说明它之前就是一个安全节点,现在成为了终端节点。
  4. 遍历完毕之后,再遍历一遍出度数组,把所有出度为0的节点更新到结果集中即可。

1.1 初始化邻接图

java 复制代码
int n = graph.length;
// 初始化邻接图和出度数组
List<Integer>[] adj = new ArrayList[n];
int[] outDegree = new int[n];
for (int i = 0; i < n; i++) {
    adj[i] = new ArrayList<>();
}

1.2 构建反向邻接图

java 复制代码
// 构建邻接图和出度数组,这里的索引就是一条有向边的起点。
for (int i = 0; i < n; i++) {
    // 出度的个数,就是二维的长度
    outDegree[i] = graph[i].length;
    // 反向构建邻接图
    for (int j = 0; j < graph[i].length; j++) {
        adj[graph[i][j]].add(i);
    }
}

1.3 BFS遍历

java 复制代码
// 将出度为0的入队
LinkedList<Integer> queue = new LinkedList<>();
for (int i = 0; i < n; i++) {
    if (outDegree[i] == 0) {
        queue.offer(i);
    }
}
while (!queue.isEmpty()) {
    int size = queue.size();
    for (int i = 0; i < size; i++) {
        Integer cur = queue.poll();
        // adj[cur] 就是 pre --> 终端节点,拿到的所有 pre
        for (Integer pre : adj[cur]) {
            // 出度 -1,若为0,继续入队
            if (--outDegree[pre] == 0) {
                queue.offer(pre);
            }
        }
    }
}

1.4 完整代码

java 复制代码
public class Test802 {
    public List<Integer> eventualSafeNodes(int[][] graph) {
        int n = graph.length;
        // 初始化邻接图和出度数组
        List<Integer>[] adj = new ArrayList[n];
        int[] outDegree = new int[n];
        for (int i = 0; i < n; i++) {
            adj[i] = new ArrayList<>();
        }
        // 构建邻接图和出度数组,这里的索引就是一条有向边的起点。
        for (int i = 0; i < n; i++) {
            // 出度的个数,就是二维的长度
            outDegree[i] = graph[i].length;
            // 反向构建邻接图
            for (int j = 0; j < graph[i].length; j++) {
                adj[graph[i][j]].add(i);
            }
        }
        // 将出度为0的入队
        LinkedList<Integer> queue = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            if (outDegree[i] == 0) {
                queue.offer(i);
            }
        }
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                Integer cur = queue.poll();
                // adj[cur] 就是 pre --> 终端节点,拿到的所有 pre
                for (Integer pre : adj[cur]) {
                    // 出度 -1,若为0,继续入队
                    if (--outDegree[pre] == 0) {
                        queue.offer(pre);
                    }
                }
            }
        }
        // 最终出度为0的全部加入到结果集中
        ArrayList<Integer> res = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (outDegree[i] == 0) {
                res.add(i);
            }
        }
        return res;
    }
}
相关推荐
tobias.b9 小时前
408真题解析-2010-7-数据结构-无向连通图
数据结构·算法·图论·计算机考研·408真题解析
世界尽头与你10 小时前
TensorBoard 未授权访问漏洞
安全·网络安全·渗透测试
良木生香10 小时前
【鼠鼠优选算法-双指针】003:快乐数 & 004:盛水最多的容器
算法
Cx330❀10 小时前
【优选算法必刷100题】第41-42题(模拟):Z 字形变换,外观数列
c++·算法
沃尔特。11 小时前
直流无刷电机FOC控制算法
c语言·stm32·嵌入式硬件·算法
CW32生态社区11 小时前
CW32L012的PID温度控制——算法基础
单片机·嵌入式硬件·算法·pid·cw32
Cx330❀11 小时前
【优选算法必刷100题】第038题(位运算):消失的两个数字
开发语言·c++·算法·leetcode·面试
漫随流水11 小时前
leetcode回溯算法(93.复原IP地址)
数据结构·算法·leetcode·回溯算法
燃于AC之乐11 小时前
我的算法修炼之路--5——专破“思维陷阱”,那些让你拍案叫绝的非常规秒解
c++·算法·贪心算法·bfs·二分答案·扩展域并查集·动态规划(最长上升子序列)
艾莉丝努力练剑11 小时前
【优选算法必刷100题】第021~22题(二分查找算法):山脉数组的峰顶索引、寻找峰值
数据结构·c++·算法·leetcode·stl