剑指 Offer II 113. 课程顺序

news/2025/3/25 21:29:02/

comments: true
edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20113.%20%E8%AF%BE%E7%A8%8B%E9%A1%BA%E5%BA%8F/README.md

剑指 Offer II 113. 课程顺序

题目描述

现在总共有 numCourses 门课需要选,记为 0 到 numCourses-1

给定一个数组 prerequisites ,它的每一个元素 prerequisites[i] 表示两门课程之间的先修顺序。 例如 prerequisites[i] = [ai, bi] 表示想要学习课程 ai ,需要先完成课程 bi 。

请根据给出的总课程数  numCourses 和表示先修顺序的 prerequisites 得出一个可行的修课序列。

可能会有多个正确的顺序,只要任意返回一种就可以了。如果不可能完成所有课程,返回一个空数组。

 

示例 1:

输入: numCourses = 2, prerequisites = [[1,0]] 
输出: [0,1]
解释: 总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。

示例 2:

输入: numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
输出: [0,1,2,3] or [0,2,1,3]
解释: 总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3]

示例 3:

输入: numCourses = 1, prerequisites = [] 
输出: [0]
解释: 总共 1 门课,直接修第一门课就可。

 

提示:

  • 1 <= numCourses <= 2000
  • 0 <= prerequisites.length <= numCourses * (numCourses - 1)
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • ai != bi
  • prerequisites 中不存在重复元素

 

注意:本题与主站 210 题相同:https://leetcode.cn/problems/course-schedule-ii/

解法

方法一:拓扑排序

拓扑排序的思路是,先统计每个节点的入度,然后从入度为 0 的节点开始,依次删除这些节点,同时更新与这些节点相连的节点的入度,直到所有节点都被删除。

这里使用队列来存储入度为 0 的节点,每次从队列中取出一个节点,将其加入结果数组中,然后遍历与这个节点相连的节点,将这些节点的入度减 1,如果减 1 后入度为 0,则将这些节点加入队列中。

最后判断结果数组的长度是否等于节点的个数,如果等于则返回结果数组,否则返回空数组。

时间复杂度 O ( n + m ) O(n + m) O(n+m),空间复杂度 O ( n + m ) O(n + m) O(n+m)。其中 n n n m m m 分别是节点的个数和边的个数。

Python3
class Solution:def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:graph=defaultdict(list)indg={} #其实目的还是为bfs第一层服务的for i in range(numCourses): #【注意】初始化,要不然第一层为空indg[i]=0 for b,a in prerequisites:graph[a].append(b)indg[b]+=1# 第一层q=deque()for node,ind in indg.items():if ind==0:q.append(node)print(q,indg)#bfsres=[]while q:for _ in range(len(q)):cur=q.popleft()res.append(cur)for nx in graph[cur]:indg[nx]-=1if indg[nx]==0:q.append(nx)return res if len(res)==numCourses else []
Java
class Solution {public int[] findOrder(int numCourses, int[][] prerequisites) {List<Integer>[] g = new List[numCourses];Arrays.setAll(g, k -> new ArrayList<>());int[] indeg = new int[numCourses];for (var p : prerequisites) {int a = p[0], b = p[1];g[b].add(a);++indeg[a];}Deque<Integer> q = new ArrayDeque<>();for (int i = 0; i < numCourses; ++i) {if (indeg[i] == 0) {q.offer(i);}}int[] ans = new int[numCourses];int cnt = 0;while (!q.isEmpty()) {int i = q.poll();ans[cnt++] = i;for (int j : g[i]) {if (--indeg[j] == 0) {q.offer(j);}}}return cnt == numCourses ? ans : new int[0];}
}
C++
class Solution {
public:vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {vector<int> g[numCourses];vector<int> indeg(numCourses);for (auto& p : prerequisites) {int a = p[0], b = p[1];g[b].push_back(a);++indeg[a];}queue<int> q;for (int i = 0; i < numCourses; ++i) {if (indeg[i] == 0) {q.push(i);}}vector<int> ans;while (q.size()) {int i = q.front();q.pop();ans.push_back(i);for (int j : g[i]) {if (--indeg[j] == 0) {q.push(j);}}}return ans.size() == numCourses ? ans : vector<int>();}
};
Go
func findOrder(numCourses int, prerequisites [][]int) []int {g := make([][]int, numCourses)indeg := make([]int, numCourses)for _, p := range prerequisites {a, b := p[0], p[1]g[b] = append(g[b], a)indeg[a]++}q := []int{}for i, v := range indeg {if v == 0 {q = append(q, i)}}ans := []int{}for len(q) > 0 {i := q[0]q = q[1:]ans = append(ans, i)for _, j := range g[i] {indeg[j]--if indeg[j] == 0 {q = append(q, j)}}}if len(ans) == numCourses {return ans}return []int{}
}
TypeScript
function findOrder(numCourses: number, prerequisites: number[][]): number[] {const g: number[][] = Array.from({ length: numCourses }, () => []);const indeg: number[] = Array(numCourses).fill(0);for (const [a, b] of prerequisites) {g[b].push(a);++indeg[a];}const q: number[] = indeg.map((v, i) => (v === 0 ? i : -1)).filter(v => v !== -1);const ans: number[] = [];while (q.length) {const i = q.pop()!;ans.push(i);for (const j of g[i]) {if (--indeg[j] === 0) {q.push(j);}}}return ans.length === numCourses ? ans : [];
}
C#
public class Solution {public int[] FindOrder(int numCourses, int[][] prerequisites) {List<int>[] g = new List<int>[numCourses];for (int i = 0; i < numCourses; i++) {g[i] = new List<int>();}int[] indeg = new int[numCourses];foreach (var p in prerequisites) {int a = p[0], b = p[1];g[b].Add(a);++indeg[a];}Queue<int> q = new Queue<int>();for (int i = 0; i < numCourses; ++i) {if (indeg[i] == 0) {q.Enqueue(i);}}int[] ans = new int[numCourses];int cnt = 0;while (q.Count > 0) {int i = q.Dequeue();ans[cnt++] = i;foreach (int j in g[i]) {if (--indeg[j] == 0) {q.Enqueue(j);}}}return cnt == numCourses ? ans : new int[0];}
}
Swift
class Solution {func findOrder(_ numCourses: Int, _ prerequisites: [[Int]]) -> [Int] {var graph = Array(repeating: [Int](), count: numCourses)var indegree = Array(repeating: 0, count: numCourses)for prereq in prerequisites {let course = prereq[0]let prereqCourse = prereq[1]graph[prereqCourse].append(course)indegree[course] += 1}var queue = [Int]()for i in 0..<numCourses {if indegree[i] == 0 {queue.append(i)}}var order = [Int]()while !queue.isEmpty {let course = queue.removeFirst()order.append(course)for nextCourse in graph[course] {indegree[nextCourse] -= 1if indegree[nextCourse] == 0 {queue.append(nextCourse)}}}return order.count == numCourses ? order : []}
}

http://www.ppmy.cn/news/1583051.html

相关文章

特征工程自动化(FeatureTools实战)

目录 特征工程自动化(FeatureTools实战)1. 引言2. 项目背景与意义2.1 特征工程的重要性2.2 自动化特征工程的优势2.3 工业级数据处理需求3. 数据集生成与介绍3.1 数据集构成3.2 数据生成方法4. 自动化特征工程理论基础4.1 特征工程的基本概念4.2 FeatureTools库简介4.3 关键公…

TensorFlow和Pytorch在功能上的区别以及优势

功能上的区别 1. 计算图 TensorFlow&#xff1a; 使用静态计算图&#xff08;Static Graph&#xff09;。在运行模型之前&#xff0c;需要先构建完整的计算图&#xff0c;然后通过会话&#xff08;Session&#xff09;运行图。 优点是性能优化更高效&#xff0c;适合大规模分…

nlohmann::json教程

nlohmann::json 核心函数和方法 1. 基础构造与初始化 函数/方法描述示例json j;创建一个空的 JSON 对象&#xff08;默认是 object 类型&#xff09;json j;json::object()显式创建一个空的 JSON 对象json j json::object();json::array()显式创建一个空的 JSON 数组json ar…

[学成在线]06-视频分片上传

上传视频 需求分析 教学机构人员进入媒资管理列表查询自己上传的媒资文件。 点击“媒资管理” 进入媒资管理列表页面查询本机构上传的媒资文件。 教育机构用户在"媒资管理"页面中点击 "上传视频" 按钮。 点击“上传视频”打开上传页面 选择要上传的文件…

OPENCV数字识别(非手写数字/采用模板匹配)

这篇文章的重点在于 模板匹配 的使用。模板匹配是计算机视觉中的一项基本技术&#xff0c;它通过比对输入图像与模板图像的相似度&#xff0c;来进行目标识别。对于数字识别&#xff0c;特别是标准数字的识别&#xff0c;模板匹配非常有效。 请看效果&#xff1a; 文章结构 …

在shell脚本内部获取该脚本所在目录的绝对路径

目录 需求描述 方法一&#xff1a;使用 dirname 和 readlink 命令 方法二&#xff1a;使用 BASH_SOURCE 变量 方法三&#xff1a;仅使用纯 Bash 实现 需求描述 工作中经常有这样情况&#xff0c;需要在脚本内部获取该脚本自己所在目录的绝对路径。 假如有一个脚本/a/b/c/…

Excel online开始支持Copilot高级数据分析:Python提供强大的数据见解

前文讲过Excel中的copilot可以直接调用Python进行高级数据分析&#xff1a; Copilot&#xff1a;Excel中的Python高级分析来了 Python in Excel高级分析&#xff1a;一键RFM分析 超越DeepSeek&#xff1a;Copilot in Excel高级数据分析原生支持Python无需安装软件 零代码、…

git,openpnp - 根据安装程序打包名称找到对应的源码版本

文章目录 git,openpnp - 根据安装程序打包名称找到对应的源码版本概述笔记备注 - 提交时间不可以作为查找提交记录的依据END git,openpnp - 根据安装程序打包名称找到对应的源码版本 概述 想在openpnp官方最新稳定版上改一改&#xff0c;首先就得知道官方打包的安装程序对应的…