你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
示例:
输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成?课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
来源:https://leetcode-cn.com/problems/course-schedule
/**从一个节点(入度为0的点)开始,深度优先访问所有节点。 但是可能一个闭环中所有节点入度为0 * 不过如果碰到环了就直接回退吧,不需要遍历完了 * @param {number} node 节点名 */ function dfs(node) { var nextNodes = adjacencyTable.get(node); if (nextNodes.length == 0) { stats.set(node, -1) //标记为已经访问 return; }; stats.set(node, 1) //标记为正在访问 for (let i = 0; i < nextNodes.length; i++) { if (result == false) return; //每次访问子节点时判断。有环则立即回退 if (stats.get(nextNodes[i]) == 0) { //未访问,向下进行 dfs(nextNodes[i]) } else if (stats.get(nextNodes[i]) == 1) { //访问到正在访问的节点。发现有环 result = false; break; } else if (stats.get(nextNodes[i]) == -1) { //已经访问过的节点,不管 continue; } } stats.set(node, -1); //最后该节点已经访问完全,设置状态-1 return; }
// 从队首开始移出元素,然后改变邻接矩阵 while (queue.length) { let current = queue.shift(); //取一个入度为0的节点 for (let j = 0; j < numCourses; j++) { //遍历这行 if (adjacencyMatrix[current][j] == 1) { adjacencyMatrix[current][j] = 0; for (let i = 0; i < numCourses; i++) { //查看删除了当前节点后 的 连接的节点是否出度为0了 if (adjacencyMatrix[i][j] == 1) { break; } else { if (i == numCourses - 1) { queue.push(j); } } } } } }
/** * @param {number} numCourses * @param {number[][]} prerequisites * @return {boolean} */ var canFinish = function (numCourses, prerequisites) { /** * ******DFS方法和Topological 深度优先与拓扑排序法****** * ** ** * ***************** * ** ** * ** ** * ********************* * ** ** ** * ** ** ** * ** ** ** * ** ** ** * ** ** ** * ******DFS方法和Topological 深度优先与拓扑排序法****** */ //1.拓扑排序解决 function Topological(numCourses, prerequisites){ //创建邻接矩阵 var adjacencyMatrix = new Array(numCourses); var queue = []; for (let i = 0; i < numCourses; i++) { adjacencyMatrix[i] = new Array(numCourses); adjacencyMatrix[i].fill(0); }; for (let i = 0; i < prerequisites.length; i++) { adjacencyMatrix[prerequisites[i][1]][prerequisites[i][0]] = 1; } //找到入度为0的点入队列 遍历j:0->n列; for (let j = 0; j < numCourses; j++) { let count = 0; for (let i = 0; i < numCourses; i++) if (adjacencyMatrix[i][j] == 1) count++; if (count == 0) queue.push(j); } //从队首开始移出元素,然后改变邻接矩阵 while (queue.length) { let current = queue.shift(); for (let j = 0; j < numCourses; j++) { if (adjacencyMatrix[current][j] == 1) { adjacencyMatrix[current][j] = 0; for (let i = 0; i < numCourses; i++) { if (adjacencyMatrix[i][j] == 1) { break; } else { if (i == numCourses - 1) { queue.push(j); } } } } } } //查看矩阵是否全为0; for (let i = 0; i < numCourses; i++) { for (let j = 0; j < numCourses; j++) { if (adjacencyMatrix[i][j] == 1) return false; } if (i == numCourses - 1) return true; } } //2.深度优先DFS遍历,只要不存在环,就成功 function DFS(numCourses, prerequisites) { /**从一个节点(入度为0的点)开始,深度优先访问所有节点。 但是可能一个闭环中所有节点入度为0 * 不过如果碰到环了就直接回退吧,不需要遍历完了 * @param {number} node 节点名 */ function dfs(node) { var nextNodes = adjacencyTable.get(node); if (nextNodes.length == 0) { stats.set(node, -1) return; }; stats.set(node, 1) for (let i = 0; i < nextNodes.length; i++) { if (result == false) return; if (stats.get(nextNodes[i]) == 0) { dfs(nextNodes[i]) } else if (stats.get(nextNodes[i]) == 1) { result = false; break; } else if (stats.get(nextNodes[i]) == -1) { continue; } } stats.set(node, -1); return; } //创建邻接表 var adjacencyTable = new Map() var queue = new Array(numCourses) //记录节点入度数 queue.fill(0) //初始化入度为0的点值为0。 var stats = new Map(); //key:节点,value:访问状态。0未被访问,1正在访问,-1已经被其他访问 //最后状态全为-1,则表示访问完了。 var result = true; //记录是否有环。和是否全部访问完。true 为遍历到的节点是无环的 for (let i = 0; i < numCourses; i++) { adjacencyTable.set(i, []); stats.set(i, 0); } for (let i = 0; i < prerequisites.length; i++) { adjacencyTable.get(prerequisites[i][1]).push(prerequisites[i][0]); } // console.log(‘邻接表:‘, adjacencyTable) //找出入度为0的点 adjacencyTable.forEach((val, key) => { val.forEach((item, index) => { queue[item]++ }) }) // console.log(‘入度数:‘, queue) //从每个入度为0的点开始遍历图 queue.forEach((item, index) => { if (item == 0) { dfs(index); } }) //查看状态; if (result == false) return false; // console.log(‘最终状态:‘, stats) for (let i = 0; i < stats.size; i++) { if (stats.get(i) == 0) return false; } return true; } //调用 //调用 //调用 //调用 //1.拓扑排序解决 // return Topological(numCourses, prerequisites); //2.DFS深度优先 return DFS(numCourses, prerequisites) };
原文:https://www.cnblogs.com/home-zhuxing/p/12487778.html