程序员社区

LeetCode-207-课程表

LeetCode-207-课程表

207. 课程表

难度中等

你这个学期必须选修 numCourses 门课程,记为 0numCourses - 1

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai必须 先学习课程 bi

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false

示例 1:

输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。

示例 2:

输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。

提示:

  • 1 <= numCourses <= 105
  • 0 <= prerequisites.length <= 5000
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • prerequisites[i] 中的所有课程对 互不相同

拓扑排序问题
根据依赖关系,构建邻接表、入度数组。
选取入度为 0 的数据,根据邻接表,减小依赖它的数据的入度。
找出入度变为 0 的数据,重复第 2 步。
直至所有数据的入度为 0,得到排序,如果还有数据的入度不为 0,说明图中存在环

class Solution {
    // 一个node,就是一个课程
    // name是课程的编号
    // in是课程的入度
    public static class Node {
        public int name;
        public int in;
        public ArrayList<Node> nexts;

        public Node(int n) {
            name = n;
            in = 0;
            nexts = new ArrayList<>();
        }
    }

    public static boolean canFinish(int numCourses, int[][] prerequisites) {
        if (prerequisites == null || prerequisites.length == 0) {
            return true;
        }
        HashMap<Integer, Node> nodes = new HashMap<>();
        for (int[] arr : prerequisites) {
            int to = arr[0];
            int from = arr[1];
            if (!nodes.containsKey(to)) {
                nodes.put(to, new Node(to));
            }
            if (!nodes.containsKey(from)) {
                nodes.put(from, new Node(from));
            }
            Node t = nodes.get(to);
            Node f = nodes.get(from);
            f.nexts.add(t);
            t.in++;
        }
        int needPrerequisiteNums = nodes.size();
        Queue<Node> zeroInQueue = new LinkedList<>();
        for (Node node : nodes.values()) {
            if (node.in == 0) {
                zeroInQueue.add(node);
            }
        }
        int count = 0;
        while (!zeroInQueue.isEmpty()) {
            Node cur = zeroInQueue.poll();
            count++;
            for (Node next : cur.nexts) {
                if (--next.in == 0) {
                    zeroInQueue.add(next);
                }
            }
        }
        return count == needPrerequisiteNums;
    }
}
LeetCode-207-课程表插图
image-20210623123609282

拓扑排序问题的解决办法是主要是循环执行以下两步,直到不存在入度为0的顶点为止。

    1. 选择一个入度为0的顶点并输出之;
    1. 从网中删除此顶点及所有出边。

循环结束后,若输出的顶点数小于网中的顶点数,则输出“有回路”信息,即无法完成所有任务;否则输出的顶点序列就是一种拓扑序列,即可以完成所有任务。

// AOV 网的拓扑排序
func canFinish(n int, pre [][]int) bool {
    in := make([]int, n)
    frees := make([][]int, n)
    next := make([]int, 0, n)
    for _, v := range pre {
        in[v[0]]++
        frees[v[1]] = append(frees[v[1]], v[0])
    }
    for i := 0; i < n; i++ {
        if in[i] == 0 {
            next = append(next, i)
        }
    }
    for i := 0; i != len(next); i++ {
        c := next[i]
        v := frees[c]
        for _, vv := range v {
            in[vv]--
            if in[vv] == 0 {
                next = append(next, vv)
            }
        }
    }
    return len(next) == n
}
LeetCode-207-课程表插图1
image-20210623123918452
赞(0) 打赏
未经允许不得转载:IDEA激活码 » LeetCode-207-课程表

一个分享Java & Python知识的社区