图 - 拓扑排序 - 课程安排的合法性

这篇博客介绍了如何解决LeetCode上的207号问题——课程表。通过两种方法,深度优先搜索(DFS)和入度表(BFS),检查是否存在有向无环图来确定课程是否能按顺序完成。DFS方法通过递归遍历课程依赖,BFS方法使用队列处理无前置课程的节点,逐步减少课程数量。两种方法的时间复杂度均为O(N+M),空间复杂度为O(N+M)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.题目

LeetCode: 207. 课程表

【medium】

2.解题

方法一:DFS

参考:

https://leetcode-cn.com/problems/course-schedule/solution/ke-cheng-biao-by-leetcode-solution/

java:

class Solution {
    List<List<Integer>> edges;
    int[] visited;
    boolean valid = true;

    public boolean canFinish(int numCourses, int[][] prerequisites) {
        edges = new ArrayList<List<Integer>>();
        for (int i = 0; i < numCourses; ++i) {
            edges.add(new ArrayList<Integer>());
        }
        visited = new int[numCourses];
        for (int[] info : prerequisites) {
            edges.get(info[1]).add(info[0]);
        }
        for (int i = 0; i < numCourses && valid; i++) {
            if (visited[i] == 0) dfs(i);
        }
        return valid;
    }

    public void dfs(int i) {
        visited[i] = 1;
        for (int j : edges.get(i)) {
            if (visited[j] == 0) {
                dfs(j);
                if (!valid) return;
            } else if (visited[j] == 1) {
                valid = false;
                return;
            }
        }
        visited[i] = 2;
    }
}

方法二:入度表(BFS)

参考:

https://leetcode-cn.com/problems/course-schedule/solution/course-schedule-tuo-bu-pai-xu-bfsdfsliang-chong-fa/

可以将本题转换成是否存在有向无环图的问题,因为安排课程的结果是一个拓扑排序不应该存在有向无环图,否则无法安排课程。

故首先统计每个节点的入度,并生成入度表,入度为0的节点(课程)没有前置课程。然后借助队列将所有入度为0的节点入队。当队列非空时,依次将队首节点出队,并且将与其邻接的节点入度-1,当邻接节点入度-1后为0则代表已完成前置课程,将其入队,以此类推,每次出队时将numCourses–,直至最后如果numCourses为0则代表可以完成所有课程,否则返回false。

java:

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        int[] indegrees = new int[numCourses];
        Queue<Integer> queue = new LinkedList<>();
        List<List<Integer>> edges = new ArrayList<>();
        for (int i = 0; i < numCourses; i++) edges.add(new ArrayList<>());
        for (int[] info : prerequisites) {
            indegrees[info[0]]++;
            edges.get(info[1]).add(info[0]);
        }
        for (int i = 0; i < numCourses; i++) {
            if (indegrees[i] == 0) queue.add(i);
        }
        while (!queue.isEmpty()) {
            int pre = queue.poll();
            numCourses--;
            for (int cur : edges.get(pre)) {
                if (--indegrees[cur] == 0) queue.add(cur);
            }
        }
        return numCourses == 0;
    }
}

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

空间复杂度 O(N + M) 为建立邻接表所需额外空间,edges 长度为 N ,并存储 M 条临边的数据。

疑问

edges.get(info[1]).add(info[0]);

该语句的执行结果是每门课程依赖他的课程列表

比如:

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

结果是

[[1, 2, 3], [3], [], []]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值