想要精通算法和SQL的成长之路 - 课程表IV

想要精通算法和SQL的成长之路 - 课程表IV

  • 前言
  • [一. 课程表IV (拓扑排序)](#一. 课程表IV (拓扑排序))

前言

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

做这个题目之前可以回顾一下:课程表II

一. 课程表IV (拓扑排序)

原题链接

这道题目在课程表II的基础上做了什么升华呢?也就是课程之间的先决条件是可以继承的。 那么我们在原本的拓扑排序基础上可以做些什么操作?

  • 我们需要记录这个先决关系,记录每一对课程之间是否存在直接或间接的先决条件。这里我们可以用一个二维数组matrix来存储。
  • 最终的返回结果,根据queries数组的一二维坐标可以直接查询。

我们先看下拓扑排序中的几个重要步骤:

1.构建邻接图以及计算每个节点的入度数。

java 复制代码
List[] adj = new List[numCourses];
// 初始化集合而已
for (int i = 0; i < numCourses; i++) {
    adj[i] = new ArrayList<Integer>();
}
int[] inDegree = new int[numCourses];
for (int[] prerequisite : prerequisites) {
	// [0,1] --> 0->1
    adj[prerequisite[0]].add(prerequisite[1]);
    // 后继节点的入度+1
    inDegree[prerequisite[1]]++;
}

2.利用queue队列,将入度为0的先入队,并做后续的递归操作。入度为0,则说明没有先决课程,可以直接学习。

java 复制代码
LinkedList<Integer> queue = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
    if (inDegree[i] == 0) {
        queue.offer(i);
    }
}

3.开始递归:

java 复制代码
while (!queue.isEmpty()) {
    Integer pre = queue.poll();
    List<Integer> nextNode = adj[pre];
    for (Integer next : nextNode) {
    	// 入度-1
        inDegree[next]--;
        // 入度为0之后,立马加入队列,进入下一次递归
        if (inDegree[next] == 0) {
            queue.offer(next);
        }
    }
}

那么本题目将在第三个步骤中增添核心逻辑:

  1. 我们准备一个二维数组matrix
  2. 同时在递归过程中,将对应的指向关系设置为true,代表他们之间的有向性 pre --> next。如果说存在节点 i --> pre。那么一定有i --> next
java 复制代码
boolean[][] matrix = new boolean[numCourses][numCourses];
while (!queue.isEmpty()) {
    Integer pre = queue.poll();
    List<Integer> nextNode = adj[pre];
    for (Integer next : nextNode) {
    	// 当前的有向性
        matrix[pre][next] = true;
        // 同时遍历一次数组,在满足pre->next的前提下,如果有i->pre。必定有i->next (i->pre->next)
        // 注意,这里的遍历,我们的纵坐标是固定的,因为纵坐标是指向地(后继节点),而出发点我们应该遍历所有的情况
        for (int i = 0; i < numCourses; i++) {
            if (matrix[i][pre]) {
                matrix[i][next] = true;
            }
        }
        inDegree[next]--;
        if (inDegree[next] == 0) {
            queue.offer(next);
        }
    }
}

最后根据题目的入参queries,像查字典一样,从matrix字典中查出每组的答案:

java 复制代码
ArrayList<Boolean> res = new ArrayList<>();
for (int[] query : queries) {
    res.add(matrix[query[0]][query[1]]);
}
return res;

最终完整代码如下:

java 复制代码
public class Test1462 {
    public List<Boolean> checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) {
        List[] adj = new List[numCourses];
        boolean[][] matrix = new boolean[numCourses][numCourses];
        for (int i = 0; i < numCourses; i++) {
            adj[i] = new ArrayList<Integer>();
        }
        int[] inDegree = new int[numCourses];
        for (int[] prerequisite : prerequisites) {
            adj[prerequisite[0]].add(prerequisite[1]);
            inDegree[prerequisite[1]]++;
        }
        LinkedList<Integer> queue = new LinkedList<>();
        for (int i = 0; i < numCourses; i++) {
            if (inDegree[i] == 0) {
                queue.offer(i);
            }
        }
        while (!queue.isEmpty()) {
            Integer pre = queue.poll();
            List<Integer> nextNode = adj[pre];
            for (Integer next : nextNode) {
                matrix[pre][next] = true;
                for (int i = 0; i < numCourses; i++) {
                    if (matrix[i][pre]) {
                        matrix[i][next] = true;
                    }
                }
                inDegree[next]--;
                if (inDegree[next] == 0) {
                    queue.offer(next);
                }
            }
        }
        ArrayList<Boolean> res = new ArrayList<>();
        for (int[] query : queries) {
            res.add(matrix[query[0]][query[1]]);
        }
        return res;
    }
}
相关推荐
ARM|X86+FPGA工业主板厂家2 分钟前
基于嵌入式 GPU 的智能服务机器人
linux·运维·arm开发·fpga开发·机器人
余额瞒着我当琳6 分钟前
算法修炼 chapter 2 双指针进阶、盛最多水的容器、有效三角形的个数、两数之和、三数之和、四数之和
算法
你压到我腿毛了6668 分钟前
C语言冒泡算法(Bubble sort)
c语言·数据结构·算法
sulikey13 分钟前
Linux 粘滞位(Sticky Bit)完全指南:为什么共享目录需要“防删除“?
linux·服务器
mengge.cloud14 分钟前
网络技术基础小白教程
linux·服务器·网络·云计算
学代码的CJY32 分钟前
Linux 重定向、管道与环境变量
linux·spring boot·spring
靠沿1 小时前
贪心算法专题(三)
算法·贪心算法
treacle田1 小时前
达梦数据库-Linux DM数据守护主备集群缩改为单机-记录总结
linux·服务器·数据库·主备集群改单机
super大力张1 小时前
MOE基于结构的药物设计(七):Ligand R-Vectors——如何判断配体可以从哪里继续生长?
数据库·算法·cadd·moe·svl·基于结构的药物设计
Databend1 小时前
Databend 增量物化视图:基于 Change Tracking 的增量刷新与一致性读取
大数据·数据库·sql