[路飞]~拓扑排序之课程表

175 阅读3分钟

首先对拓扑排序,我是相当陌生的,此篇仅此记录一下有趣的拓扑排序算法思路

拓扑排序

通过简单粗暴的了解后,大致我是这么理解的:
有一处猛料 由 A选手,B选手散播出去 散播路线如下

拓扑排序例子说明图.001.jpeg

A 告诉了 D D选手只有A的消息来源 所以选择了相信 B 告诉了 C A 又 告诉了C 那C选手也相信了这消息 那么以此类推,D 依赖于A的消息, C 依赖于 A 与 B的消息 少一个C都会怀疑此消息的真实性,这就是拓扑图带来的连带关系

207. 课程表

那么今天的主角 力扣的课程表题目就很好诠释了这种算法思想,想贴题目如下 你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程  bi 。 能完成所有课程返回true, 否则返回false

简明扼要的说就是:

  1. 一共有n门课程要上,编号从0开始
  2. 有先决条件[1,0] 意思就是必须先上课程0 才能上课程1,与上述所说的消息传播依赖关系类似

举个例子: n = 6, 先决条件:[1,0][2,0][3,2][4,2][5,4][5,3]

未命名.001.jpeg

先上0课程才能上课程1,课程2
课程1 了才能上课程3
课程2 上了才能上课程4
课程4 与 课程3 都上了才能上课程5 这图专业名词应该说有向无环图,如果是有环的那说明无法完成所有课程 在这里表示的话
然后有向图又入度出度的概念
按我的理解,入度就是此时,此课程你受什么限制,比如课程0 入度就是0 因为不受限制,但是出度为2 ,出度我理解的就是限制了谁,那这里课程0 限制了课程1 与课程2


那解题思路就来了: 每次只能选入度为0的课程,如果多个为0的课程这里顺序不受限, 假设选择了课程0,那课程1入度由1变为0,课程2也是如此 接着选课程1,导致课程3入度变为0,紧接着课程5的入度也就有2变为1 接着选课程2,导致课程4入度变为0,那么课程5的入度也变为0了,至此选不到入度不为0的课程了

const canFinish = (numCourses, prerequisites) => {
  const inDeg = new Array(numCourses).fill(0); // 入度数组
  const map = {};                                 // 邻接表
  for (let i = 0; i < prerequisites.length; i++) {
    inDeg[prerequisites[i][0]]++;              // 求课的初始入度值
    if (map[prerequisites[i][1]]) {               // 当前课已经存在于邻接表
      map[prerequisites[i][1]].push(prerequisites[i][0]); // 添加依赖它的后续课
    } else {                                      // 当前课不存在于邻接表
      map[prerequisites[i][1]] = [prerequisites[i][0]];
    }
  }
  const queue = [];
  for (let i = 0; i < inDeg.length; i++) { // 所有入度为0的课入列
    if (inDeg[i] == 0) queue.push(i);
  }
  let count = 0;
  while (queue.length) {
    const selected = queue.shift();           // 当前选的课,出列
    count++;                                  // 选课数+1
    const toEnQueue = map[selected];          // 获取这门课对应的后续课
    if (toEnQueue && toEnQueue.length) {      // 确实有后续课
      for (let i = 0; i < toEnQueue.length; i++) {
        inDeg[toEnQueue[i]]--;             // 依赖它的后续课的入度-1
        if (inDeg[toEnQueue[i]] == 0) {    // 如果因此减为0,入列
          queue.push(toEnQueue[i]);
        }
      }
    }
  }
  return count == numCourses; // 选了的课等于总课数,true,否则false
};