leetcode每日一题(2020-05-17):210. 课程表 II

题目描述:
现在你总共有 n 门课需要选,记为 0 到 n-1。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。
可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。

今日学习:
1.图的表示法
2.DFS和BFS
3.复习Set、splice
4.数组的交、并、补集

题解1:(又是我失败的题解Orz)

var findOrder = function(numCourses, prerequisites) {
    //我自己的想法,果然又失败了Orz
    if(prerequisites.length == 0){return [];}
    var ord = [];
    function find(numCourses, prerequisites){
        if(prerequisites.length == 1){
            ord.push(prerequisites[0][1]);
            ord.push(prerequisites[0][0]);  
            if(ord.length == numCourses){     
                return ord;
            }else{
                return [];
            }
        }else if(prerequisites.length > 1){
            var pre = new Set();
            var later = new Set();
            //pre为先序课程,later为后序课程
            for(var i = 0; i < prerequisites.length; i++){
                pre[i] = prerequisites[i][1];
                later[i] = prerequisites[i][0];
            }
            //后序课程与先序课程集合不重叠时结束
            var preArr = [...pre], laterArr = [...later];
            let intersection = preArr.filter(function (val) { return laterArr.indexOf(val) > -1 });
            if(intersection === []){
                for(var i = 0; i < pre.size; i++){
                ord.push(pre[i])
                }
                for(var i = 0; i < later.size; i++){
                ord.push(later[i])
                }
                return ord;
            }
            //只保留最根源的先序课程
            for(var i = 0; i < later.size; i++){
                if(later.has(pre[i])){
                    pre.delete(pre[i])
                }
            }
            //将最根源的先序课程推入结果数组中
            ord.push(pre[0]);
            //将含有先序课程的课程对从先决条件中删除
            for(var i = 0; i < prerequisites.length; i++){
                var toDel = prerequisites[i]; 
                if(prerequisites[i].indexOf(pre[0]) != -1){
                    var del = prerequisites.indexOf(toDel);
                    prerequisites.splice(del, 1);
                }
            }
            //开始新一轮查找
            find(numCourses, prerequisites);
        }
    }
    var ordRes = find(numCourses, prerequisites);
    return ordRes;
};

我的想法是每一次都把先序课程找出来,然后从prerequisites中删除该课程对再开始新一轮查找,但是局限性太大,很多情况不一定包含的进去
题解2:参考

var findOrder = (numCourses, prerequisites) => {
  let inDegree = new Array(numCourses).fill(0) // 初始化入度数组
  let graph = {} // 哈希表
  for (let i = 0; i < prerequisites.length; i++) {
    inDegree[prerequisites[i][0]]++ // 构建入度数组
    if (graph[prerequisites[i][1]]) { // 构建哈希表
      graph[prerequisites[i][1]].push(prerequisites[i][0])
    } else {
      let list = []
      list.push(prerequisites[i][0])
      graph[prerequisites[i][1]] = list
    }
  }
  let res = [] // 结果数组
  let queue = [] // 存放 入度为0的课
  for (let i = 0; i < numCourses; i++) { // 起初推入所有入度为0的课
    if (inDegree[i] === 0) queue.push(i)
  }
  while (queue.length) { // 没有了入度为0的课,没课可选,结束循环
    let cur = queue.shift() // 出栈,代表选这门课
    res.push(cur) // 推入结果数组
    let toEnQueue = graph[cur] // 查看哈希表,获取对应的后续课程
    if (toEnQueue && toEnQueue.length) { // 确保有后续课程
      for (let i = 0; i < toEnQueue.length; i++) { // 遍历后续课程
        inDegree[toEnQueue[i]]-- // 将后续课程的入度 -1
        if (inDegree[toEnQueue[i]] == 0) { // 一旦减到0,让该课入列
          queue.push(toEnQueue[i])
        }
      }
    }
  }
  return res.length === numCourses ? res : [] // 选齐了就返回res,否则返回[]
};

猜你喜欢

转载自www.cnblogs.com/autumn-starrysky/p/12905785.html