zoukankan      html  css  js  c++  java
  • Leetcode207--->课程表(逆拓扑排序)

    题目: 课程表,有n个课程,[0, n-1];在修一个课程前,有可能要修前导课程;

    举例:

    2, [[1,0]]  修课程1前需要先修课程0

    There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.

    2, [[1,0],[0,1]]  

    There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.

    解题思路:

    其本质是逆拓扑排序,因此首先要将给定的课程关系转换为邻接表存储,即将给定的图转化为邻接表;

    举例说明:

    4, [[1,0],[2,0],[3,1],[3,2]]

    1) 代码5的for循环是为了初始化一个邻接链表的结构,[[],[],[],[],]
    2) 代码10的for循环是为了找到有那几个节点要依靠当前节点;其中prerequisites[0][1] = 0,prerequisites[0][0] = 1,表示课程1要依靠课程0;prerequisites[1][1] = 0,prerequisites[1][0] = 2,表示课程2依靠课程0;以此类推,则最终posts中的结果为:
    [[1,2],[3],[3],[]]表示课程1,2依靠课程0,课程3依靠课程1,课程3依靠课程2,没有课程依靠课程3;
    3) 代码15声明了一个数组preNums,下面代码16的for循环来告诉我们这个数组是干什么的;
    4) 代码16的for循环中,拿出post中的每一个set,假设此时拿出的是post.get(0),则拿出的是依靠0课程才能修完课程的集合[1,2];该循环结束后,preNums=[0,1,1,2]表示0课程不依赖其他课程(0课程的出度为0),1课程依赖一个课程,2课程依赖一个课程,3课程依赖两个课程;因此preNums数组表示下标的课程依赖几个其他的课程
    5) 到此为止,我们记录了下标课程被哪几个课程依赖,即posts;下标课程自己依赖几个课程,即preNums数组;到这里可以看出我们使用的逆拓扑结构的思想;即找出preNums数组中为0的那个下标课程(在图中表示出度为0),代码27行的for循环就是干这个事情的;
    6) 假设此时没有找到出度为0的那个课程,则表示课程中有相互依赖的情况,则直接return false; 如果找到出度为0的那个课程,在此例子中为课程0,而此时课程0在post中可以得出其被[1,2]课程依赖,因此需要删除0节点,那么相应的也要删掉课程1和课程2分别对课程0的依赖,那此时,需要更新preNums数组,即1课程所依赖的课程数减一,
    2课程所依赖的课程数减一,则此时preNums = [-1, 0, 0, 2],-1表示已经删除了0节点。循环5,6)则可以判断中课程是否可以顺利修完,即给出的数组是否是一个逆拓扑结构;
     1 public class Solution {
     2     public boolean canFinish(int numCourses, int[][] prerequisites) {
     3         // init the adjacency list
     4         List<Set> posts = new ArrayList<Set>();
     5         for (int i = 0; i < numCourses; i++) {
     6             posts.add(new HashSet<Integer>());
     7         }
     8 
     9         // fill the adjacency list,找到有哪几个点要依靠该点
    10         for (int i = 0; i < prerequisites.length; i++) {
    11             posts.get(prerequisites[i][1]).add(prerequisites[i][0]);
    12         }
    13 
    14         // count the pre-courses
    15         int[] preNums = new int[numCourses];  // 计算下标的课程依赖几个课程
    16         for (int i = 0; i < numCourses; i++) {
    17             Set set = posts.get(i);
    18             Iterator<Integer> it = set.iterator();
    19             while (it.hasNext()) {
    20                 preNums[it.next()]++;
    21             }
    22         }
    23         // remove a non-pre course each time
    24         for (int i = 0; i < numCourses; i++) {
    25             // find a non-pre course
    26             int j = 0;
    27             for ( ; j < numCourses; j++) {   // 找到出度为0的点,删掉,并更新依靠该点的前驱点的个数
    28                 if (preNums[j] == 0) break;
    29             }
    30 
    31             // if not find a non-pre course
    32             if (j == numCourses) return false;
    33 
    34             preNums[j] = -1;
    35 
    36             // decrease courses that post the course
    37             Set set = posts.get(j);
    38             Iterator<Integer> it = set.iterator();
    39             while (it.hasNext()) {
    40                 preNums[it.next()]--;    // 删除依赖j节点的节点的出度
    41             }
    42         }
    43 
    44         return true;
    45     }
    46 }


  • 相关阅读:
    从12306.cn谈大网站架构与性能优化
    新浪微博的存储思路整理架构分享--微博架构的回顾
    多吃以上食物可以调理内分泌
    脸部护理
    美容实用小知识
    如何把网页或html内容生成图片
    互联网阅读与知识积累流程化实践分享
    怎样与人沟通?
    如何控制情绪
    如何去掉Google搜索的跳转 让你的Google搜索不被reset掉
  • 原文地址:https://www.cnblogs.com/leavescy/p/5887013.html
Copyright © 2011-2022 走看看