95 lines
3.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 课程安排 II - 拓扑排序DFS
* @param {number} numCourses - 课程总数
* @param {number[][]} prerequisites - 每一对 [a, b] 表示上课程 a 需要先完成课程 b
* @return {number[]} - 返回一个可行的课程学习顺序,如果无法完成所有课程则返回 []
*/
const findOrder = function (numCourses, prerequisites) {
return dfsTopoSort(numCourses, prerequisites);
};
/**
* 使用 DFS 实现拓扑排序,并判断是否存在环
* @param {number} numCourses
* @param {number[][]} prerequisites
* @return {number[]}
*/
function dfsTopoSort(numCourses, prerequisites) {
const graph = Array.from({ length: numCourses }, () => []); // 邻接表表示图
const visited = Array(numCourses).fill(0); // 节点状态0=未访问1=访问中2=已完成
const result = []; // 用于存放拓扑排序结果(逆序)
let hasCycle = false; // 用于标记图中是否存在环
// 构建图b -> a 表示先学 b 才能学 a
for (const [a, b] of prerequisites) {
graph[b].push(a);
}
/**
* 深度优先搜索当前节点
* @param {number} node
*/
function dfs(node) {
if (visited[node] === 1) {
// 当前节点正在访问中,说明存在环
hasCycle = true;
return;
}
if (visited[node] === 2 || hasCycle) {
// 节点已处理,或已发现环,直接返回
return;
}
visited[node] = 1; // 标记为访问中
for (const neighbor of graph[node]) {
dfs(neighbor);
}
visited[node] = 2; // 标记为已完成
result.push(node); // 所有邻居处理完后再加入结果,确保当前节点排在后面
}
// 遍历所有节点,防止图不连通
for (let i = 0; i < numCourses; i++) {
dfs(i);
}
// 如果存在环,则无法完成所有课程
return hasCycle ? [] : result.reverse();
}
/*
使用kahn算法来实现一个顶点能从其他顶点过来表明有一个入度有多少个顶点能到达这个顶点就有多少个入度这里直接copy207
修改一下即可
*/
function f2(numCourses, prerequisites) {
const graph = Array.from({ length: numCourses }, () => []);
const inDegree = Array(numCourses).fill(0);
const result = [];
// 构建图和入度表
for (const [a, b] of prerequisites) {
graph[b].push(a);
inDegree[a]++;
}
// 找出入度为零的顶点,将其加入队列
const queue = [];
for (let i = 0; i < numCourses; i++) {
if (inDegree[i] === 0) queue.push(i);
}
// 从队列中输出所有入度为零的顶点,如果输出的顶点数量和课程数量一致,表明可以拓扑排序,否则有环
while (queue.length > 0) {
const node = queue.shift();
// 将入度为零的顶点存入结果集合
result.push(node);
for (const neighbor of graph[node]) {
inDegree[neighbor]--;
if (inDegree[neighbor] === 0) queue.push(neighbor);
}
}
// 如果结果集中的顶点的数量小于numCourses那么表明有环放回[],否则返回结果集
return result.length < numCourses ? [] : result;
}