Blage's Coding Blage's Coding
Home
算法
  • 手写Spring
  • SSM
  • SpringBoot
  • JavaWeb
  • JAVA基础
  • 容器
  • Netty

    • IO模型
    • Netty初级
    • Netty原理
  • JVM
  • JUC
  • Redis基础
  • 源码分析
  • 实战应用
  • 单机缓存
  • MySQL

    • 基础部分
    • 实战与处理方案
    • 面试
  • ORM框架

    • Mybatis
    • Mybatis_Plus
  • SpringCloudAlibaba
  • MQ消息队列
  • Nginx
  • Elasticsearch
  • Gateway
  • Xxl-job
  • Feign
  • Eureka
  • 面试
  • 工具
  • 项目
  • 关于
🌏本站
🧸GitHub (opens new window)
Home
算法
  • 手写Spring
  • SSM
  • SpringBoot
  • JavaWeb
  • JAVA基础
  • 容器
  • Netty

    • IO模型
    • Netty初级
    • Netty原理
  • JVM
  • JUC
  • Redis基础
  • 源码分析
  • 实战应用
  • 单机缓存
  • MySQL

    • 基础部分
    • 实战与处理方案
    • 面试
  • ORM框架

    • Mybatis
    • Mybatis_Plus
  • SpringCloudAlibaba
  • MQ消息队列
  • Nginx
  • Elasticsearch
  • Gateway
  • Xxl-job
  • Feign
  • Eureka
  • 面试
  • 工具
  • 项目
  • 关于
🌏本站
🧸GitHub (opens new window)
  • 数组

  • 链表

  • 字符串

  • 二叉树

  • 动态规划

  • 深搜回溯

  • 数学贪心

  • 堆栈队列

  • 前缀和

  • 算法设计

    • 146.LRU缓存
    • 207. 拓扑排序
    • 10. 正则表达式匹配
    • 208. 前缀树
    • 2699. Dijkstra
    • 1483. 二进制倍增算法
    • 155. 最小栈
    • 2761. 欧拉线性筛
    • 297. 二叉树的序列化与反序列化
    • 28. KMP算法
    • 232. 用栈实现队列
    • 127. BFS广度优先搜索
    • 449. 序列化和反序列化二叉搜索树
    • 1462. floyed根可达性算法
      • 有向图的根可达性算法
        • 1.floyed
        • 2.广搜+拓扑排序
    • 2603. 节点出入度数组
    • 460. LFU 缓存
    • 1993. 树上的操作
    • 剑指 Offer 41. 数据流中的中位数
    • 剑指 Offer 59 - II. 队列的最大值
  • 位运算

  • WA

  • 算法
  • 算法设计
phan
2023-09-12
目录

1462. floyed根可达性算法

# 1462. 课程表 IV (opens new window)

# 有向图的根可达性算法

根据题意,题目要求判断两个节点是否是先决关系,本质上是判断有向图的根可达性问题。

两个节点的可达性采用以下几种数据结构:

  • 使用二维数组来维护两个节点的可达性关系,floyed[i] [j]=true表示 i 节点作为 j节点的前驱
  • 使用Map<Integer, Set<Integer>>集合映射保存节点的前驱结果,key为前驱节点,Set为所有后置节点的集合

本题目采用二维数组来结构化数据,而不使用集合映射的原因在于,Map既是更新对象又是被遍历对象,需要开辟新的空间保存已访问节点,不能随机访问两个节点之间的可达性,需要遍历Set。

# 1.floyed

简单粗暴三层for遍历所有节点,第一层枚举所有中间节点,第二层枚举起始节点,第三层枚举所有终点节点。floyed算法的精髓就是最外层控制中间节点。

算法的关键在于最外层枚举中间节点。这是从动态规划推导而来,对于第k个中间节点,任意两个节点的最短距离只有两种情况,要么通过第k个节点,要么不通过第k个节点(保留前k-1个节点的计算结果)。

class Solution {
    public List<Boolean> checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) {
        boolean[][] floyed = new boolean[numCourses][numCourses];
        for (int[] prerequisite : prerequisites) {
            floyed[prerequisite[0]][prerequisite[1]] = true;
        }
        for (int i = 0; i < numCourses; i++) {
            for (int j = 0; j < numCourses; j++) {
                for (int k = 0; k < numCourses; k++) {
                    if(floyed[j][i]&&floyed[i][k]) floyed[j][k]=true;
                }
            }
        }
        
        List<Boolean> res=new ArrayList<>();
        for(int i=0;i<queries.length;i++){
            if(floyed[queries[i][0]][queries[i][1]]) res.add(true);
            else res.add(false);
        }
        return res;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 2.广搜+拓扑排序

Map保存节点之间的前驱后继关系,val保存每个节点的入度。

  • 将入度为0的节点加入队列queue
  • 遍历队列,每次出队一个元素pre,进行如下操作:
    • 找到pre的所有直接后继节点集合
    • 建立pre与所有直接后继节点的先决关系,入度减一
    • 遍历所有节点,刷新建立新的连通性,这里是刷新到达所有节点到达上述pre后继集合的联通性。(注意这里是更新时,pre后继节点一定是作为终点)
  • 队列加入新的入度为0的节点
class Solution {
    public List<Boolean> checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) {
        Map<Integer, Set<Integer>> map = new HashMap<>();
        boolean[][] floyed = new boolean[numCourses][numCourses];
        int[] val=new int[numCourses];
        for(int i=0;i<prerequisites.length;i++){
            if(map.containsKey(prerequisites[i][0])){
                Set<Integer> set=map.get(prerequisites[i][0]);
                set.add(prerequisites[i][1]);
            }
            else{
                Set<Integer> set=new HashSet<>();
                set.add(prerequisites[i][1]);
                map.put(prerequisites[i][0],set);
            }
            val[prerequisites[i][1]]++;
        }
        
        Queue<Integer> queue = new LinkedList<>();
        for(int i=0;i<numCourses;i++){
            if(val[i]==0){
                queue.offer(i);
            }
        }
        while(!queue.isEmpty()){
            Integer pre = queue.poll();
            if (map.containsKey(pre)) {
                for (Integer curr : map.get(pre)) {
                    floyed[pre][curr] = true;
                    for (int i = 0; i < numCourses; i++) {
                        floyed[i][curr] = floyed[i][curr] || floyed[i][pre];
                    }
                    val[curr]--;
                    if(val[curr]==0) queue.offer(curr);
                }
            }
        }
        
        List<Boolean> res=new ArrayList<>();
        for(int i=0;i<queries.length;i++){
            if(floyed[queries[i][0]][queries[i][1]]) res.add(true);
            else res.add(false);
        }
        return res;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
编辑 (opens new window)
#Leetcode#算法设计
上次更新: 2023/12/15, 15:49:57
449. 序列化和反序列化二叉搜索树
2603. 节点出入度数组

← 449. 序列化和反序列化二叉搜索树 2603. 节点出入度数组→

Theme by Vdoing | Copyright © 2023-2024 blageCoder
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式