lc207 course schedule <topological sort>
course schedule算是很典型的拓扑排序问题,sedgewick老爷爷的算法课就是以course schedule作为例子的。leetcode题目点链接可以看到。
我记得这学期算法课期中考试也考到了拓扑排序,可惜那时候我刚转cs对算法的boundary不熟悉,题目简单的变了点花样(描述)我就没认出来其实就是拓扑排序。
Princeton算法课讲拓扑排序用的是dfs算法,后来和同学聊天意识到还有一种常用解法(出入度)。
lc207考察点:
1. 图的表达式
2. 拓扑排序的两种解法
3. cycle detection (只有 acyclic graph can be topological sorted)

我以前只会用dfs做这道题,dfs的cycle detection并不好想,我是看了好久才弄懂。是用了了call stack,call stack是从搜索启示节点nodeInit开始,一层一层往下加,当某个节点nodeX的neighbor nodeY也在call stack中,就说明出现了一个nodeY->....nodeX->nodeY的cycle
package topological_sort; public class CourseSchedule { private boolean[] marked; private boolean[] inCallStack; int[][] adjMat; public boolean canFinish(int numC, int[][] preq) { // transform input prerequisites into an adjacent matrix; adjMat = new int[numC][numC]; for (int i = 0; i < preq.length; i++) { adjMat[preq[i][0]][preq[i][1]] = 1; } marked = new boolean[numC]; inCallStack = new boolean[numC]; for (int i = 0; i < numC; i++) { marked[i] = false; inCallStack[i] = false; } for (int n = 0; n < numC; n++) { if (marked[n] == true) { continue; } if (dfs(n) == false) { return false; } } return true; } private boolean dfs(int n) { // visit the n^{th} node; marked[n] = true; inCallStack[n] = true; for (int i = 0; i < adjMat[n].length; i++) { // check all the neighboring nodes if (adjMat[n][i] == 0) { // not neighboring node continue; } if (inCallStack[i] == true) { // neighboring node and currently in CallStack System.out.println("node " + i + " is in CallStack"); return false; } if (marked[i] == false) { // dfs-ly visit the unmarked nodes if (dfs(i) == false) { return false; } } } inCallStack[n] = false; return true; } public static void main(String[] args) { CourseSchedule cs = new CourseSchedule(); int numCourses = 4; int[][] prerequisites = new int[4][2]; prerequisites[0] = new int[] {1, 0}; prerequisites[1] = new int[] {2, 1}; prerequisites[2] = new int[] {3, 2}; prerequisites[3] = new int[] {1, 3}; System.out.print(cs.canFinish(numCourses, prerequisites)); } }
// test result node 1 is in CallStack false
Alternatively, in-out degree方法做cycle-detection实在太容易了。nodes还没有删除完久找不到zero-indegree的node,则有cycle。
package topological_sort; // solution to CourseSchedule using in-degree and out-degree public class CourseSchedule_InOutDegree { int[][] adjMat; int[] inDegree; boolean[] isRemoved; public boolean canFinish(int numC, int[][] preq) { // setting attributes adjMat = new int[numC][numC]; inDegree = new int[numC]; for (int i = 0; i < preq.length; i++) { adjMat[preq[i][0]][preq[i][1]] = 1; inDegree[preq[i][1]]++; } isRemoved = new boolean[numC]; for (int i = 0; i < numC; i++) { isRemoved[i] = false; } // remove node/edges one by one while (pickZeroInDegree() >= 0) { removeNode(pickZeroInDegree()); } // check result; return allRemoved(); } private void removeNode(int n) { // the node n has 0 inDegree, for (int i = 0; i < adjMat[n].length; i++) { if (adjMat[n][i] == 0) { // not neighbor node continue; } inDegree[i]--; // remove that edge <n, i> } isRemoved[n] = true; } private int pickZeroInDegree() { // pick a node with zero degree. return -1 if none; for (int i = 0; i < inDegree.length; i++) { if (inDegree[i] == 0 && !isRemoved[i]) { return i; } } return -1; } private boolean allRemoved() { // check if all nodes are removed. for (int i = 0; i < isRemoved.length; i++) { if (isRemoved[i] == false) { return false; } } return true; } public static void main(String[] args) { CourseSchedule_InOutDegree cs = new CourseSchedule_InOutDegree(); int numCourses = 3; int[][] prerequisites = new int[3][2]; prerequisites[0] = new int[] {0, 1}; prerequisites[1] = new int[] {1, 2}; prerequisites[2] = new int[] {2, 0}; System.out.print(cs.canFinish(numCourses, prerequisites)); } }

浙公网安备 33010602011771号