解题思路:

本题可约化为:课程安排图是否是 有向无环图(DAG)。即课程间规定了前置条件,但不能构成任何环路,否则课程前置条件将不成立。

思路是通过 拓扑排序 判断此课程安排图是否是 有向无环图(DAG)。

拓扑排序是对 DAG 的顶点进行排序,使得对每一条有向边 (u, v),均有 u(在排序记录中)比 v 先出现。亦可理解为对某点 v而言,只有当 v 的所有源点均出现了,v才能出现。

通过课程前置条件列表 prerequisites 可以得到课程安排图的 邻接矩阵 adjacency,以下两种方法都会用到邻接矩阵。

方法1:入度表(广度优先遍历)

算法流程:

统计课程安排图中每个节点的入度,生成 入度表 indegrees。

借助一个队列 queue,将所有入度为 00 的节点入队。

当 queue 非空时,依次将队首节点出队,在课程安排图中删除此节点 pre:

并不是真正从邻接表中删除此节点 pre,而是将此节点对应所有邻接节点 cur 的入度 -1,即 indegrees[cur] -= 1。

当入度 -1后邻接节点 cur 的入度为 00,说明 cur 所有的前驱节点已经被 “删除”,此时将 cur 入队。

在每次 pre 出队时,执行 numCourses--;

若整个课程安排图是有向无环图(即可以安排),则所有节点一定都入队并出队过,即完成拓扑排序。换个角度说,若课程安排图中存在环,一定有节点的入度始终不为 0。

因此,拓扑排序出队次数等于课程个数,返回 numCourses == 0 判断课程是否可以成功安排。

复杂度分析:

时间复杂度 O(N + M),遍历一个图需要访问所有节点和所有临边,N 和 M分别为节点数量和临边数量;

空间复杂度 O(N),为建立邻接矩阵所需额外空间

class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
int[] indegrees = new int[numCourses];
for(int[] cp : prerequisites) indegrees[cp[0]]++;
LinkedList<Integer> queue = new LinkedList<>();
for(int i = 0; i < numCourses; i++){
if(indegrees[i] == 0) queue.addLast(i);
}
while(!queue.isEmpty()) {
Integer pre = queue.removeFirst();
numCourses--;
for(int[] req : prerequisites) {
if(req[1] != pre) continue;
if(--indegrees[req[0]] == 0) queue.add(req[0]);
}
}
return numCourses == 0;
}

}

方法2:深度优先遍历

算法流程(思路是通过 DFS 判断图中是否有环):

借助一个标志列表 flags,用于判断每个节点 i (课程)的状态:

未被 DFS 访问:i == 0;

已被其他节点启动的DFS访问:i == -1;

已被当前节点启动的DFS访问:i == 1。

对 numCourses 个节点依次执行 DFS,判断每个节点起步 DFS 是否存在环,若存在环直接返回 False。DFS 流程;

终止条件:

当 flag[i] == -1,说明当前访问节点已被其他节点启动的 DFS 访问,无需再重复搜索,直接返回 True。

当 flag[i] == 1,说明在本轮 DFS 搜索中节点 i 被第 2次访问,即 课程安排图有环,直接返回 False。

将当前访问节点 i 对应 flag[i] 置 1,即标记其被本轮 DFS 访问过;

递归访问当前节点 i 的所有邻接节点 j,当发现环直接返回 False;

当前节点所有邻接节点已被遍历,并没有发现环,则将当前节点 flag 置为 -1 并返回 True。

若整个图 DFS 结束并未发现环,返回 True。

复杂度分析:

时间复杂度 O(N + M):遍历一个图需要访问所有节点和所有临边,N 和 M分别为节点数量和临边数量;

空间复杂度 O(N),为建立邻接矩阵所需额外空间。

class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
int[][] adjacency = new int[numCourses][numCourses];
int[] flags = new int[numCourses];
for(int[] cp : prerequisites)
adjacency[cp[1]][cp[0]] = 1;
for(int i = 0; i < numCourses; i++){
if(!dfs(adjacency, flags, i)) return false;
}
return true;
}
private boolean dfs(int[][] adjacency, int[] flags, int i) {
if(flags[i] == 1) return false;
if(flags[i] == -1) return true;
flags[i] = 1;
for(int j = 0; j < adjacency.length; j++) {
if(adjacency[i][j] == 1 && !dfs(adjacency, flags, j)) return false;
}
flags[i] = -1;
return true;
}

}

leetocode 207 课程表的更多相关文章

  1. Java实现 LeetCode 207 课程表

    207. 课程表 现在你总共有 n 门课需要选,记为 0 到 n-1. 在选修某些课程之前需要一些先修课程. 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1] ...

  2. Leetcode 207.课程表

    课程表 现在你总共有 n 门课需要选,记为 0 到 n-1. 在选修某些课程之前需要一些先修课程. 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1] 给定课程总 ...

  3. leetcode.图.207课程表-Java

    1. 具体题目 现在你总共有 n 门课需要选,记为 0 到 n-1.在选修某些课程之前需要一些先修课程. 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1].给定 ...

  4. leetcode 207课程表

    class Solution { public: bool canFinish(int numCourses, vector<vector<int>>& prerequ ...

  5. [LeetCode] 207. 课程表(拓扑排序,BFS)

    题目 现在你总共有 n 门课需要选,记为 0 到 n-1. 在选修某些课程之前需要一些先修课程. 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1] 给定课程总量 ...

  6. [LeetCode] 210. 课程表 II

    题目链接:https://leetcode-cn.com/problems/course-schedule-ii/ 题目描述: 现在你总共有 n 门课需要选,记为 0 到 n-1. 在选修某些课程之前 ...

  7. Swift LeetCode 目录 | Catalog

    请点击页面左上角 -> Fork me on Github 或直接访问本项目Github地址:LeetCode Solution by Swift    说明:题目中含有$符号则为付费题目. 如 ...

  8. LeetCode刷题总结-排序、并查集和图篇

    本文介绍LeetCode上有关排序.并查集和图的算法题,推荐刷题总数为15道.具体考点分析如下图: 一.排序 1.数组问题 题号:164. 最大间距,难度困难 题号:324. 摆动排序 II,难度中等 ...

  9. leetcode探索高级算法

    C++版 数组和字符串 正文 链表: 正文 树与图: 树: leetcode236. 二叉树的最近公共祖先 递归(先序) leetcode124二叉树最大路径和 递归 图: leetcode 547朋 ...

随机推荐

  1. Subarray Sum II

    Description Given an positive integer array A and an interval. Return the number of subarrays whose ...

  2. 洛谷 P2571 [SCOI2010]传送带 题解

    每日一题 day51 打卡 Analysis 这道题是用非常恶心的三分套三分做的,有一个技巧是不要枚举坐标,枚举两条线段构成三角形的相似比就好了. 了解思路就还挺好写的(尽管我还调了三天) #incl ...

  3. WinDbg常用命令系列---!envvar

    !envvar 简介 !envvar扩展命令显示特定环境变量的值. 使用形式 !envvar Variable 参数 Variable指定显示其值的环境变量.变量不区分大小写. 环境 Windows ...

  4. 分库分表相关 - hash与range结合去分库分表

    相关文章1 整体看下来通过hash取模去分库,然后根据range去分到哪个区间的表中. 具体还要实践下来.

  5. HTML5之contenteditable可编辑属性

    运用contenteditable实现输入框高度自动增加,输入框标题name相对高度自动居中,代码如下: <!DOCTYPE html> <html> <head> ...

  6. linux高性能服务器编程 (一) --Tcp/Ip协议族

    前言: 在学习swoole入门基础的过程中,遇到了很多知识瓶颈,比方说多进程.多线程.以及进程池和线程池等都有诸多的疑惑.之前也有学习相关知识,但只是单纯的知识面了解.而没有真正的学习他们的来龙去脉. ...

  7. SDN阅读作业(二)

    前言碎碎念 当我看到这个全英论文以后,身体和心理都出现了戒断反应,让人无比难受,毕竟自己很久没做过英语阅读理解了.总之,在舍友大佬的帮助下以及各款翻译软件的鼎力支持之下(通篇读完后还是找了中文文献来对 ...

  8. vue on-change 如果有循环的timer 则无限自动执行

    <div class="contract-class"> <Checkbox v-model="smallChecked" :on-chang ...

  9. POP IM 产品分析报告

    一.   体验环境 产品名称:POP IM 软件版本:v2.4.0 手机系统:一加5T Android 9 体验时间:2019.10.22-2019.10.31 二.   产品简介 1.   产品定位 ...

  10. 并发下sftp连接报错——com.jcraft.jsch.JSchException: connection is closed by foreign host

    当对单接口极限测试时,随着并发量上升,接口稳定性出现不稳定的情况,排查后台日志,发现报错在该接口调用sftp上传时出现问题(确切的是在初始化连接时失败) 原因:系统SSH终端连接数配置过小,查看虚拟机 ...