lc207 course schedule

course schedule算是很典型的拓扑排序问题,sedgewick老爷爷的算法课就是以course schedule作为例子的。leetcode题目点链接可以看到。

我记得这学期算法课期中考试也考到了拓扑排序,可惜那时候我刚转cs对算法的boundary不熟悉,题目简单的变了点花样(描述)我就没认出来其实就是拓扑排序。
Princeton算法课讲拓扑排序用的是dfs算法,后来和同学聊天意识到还有一种常用解法(出入度)。

lc207考察点:

  • 图的表达式
  • 拓扑排序的两种解法
  • cycle detection (只有 acyclic graph can be topological sorted)
lc207 course schedule <topological sort>_第1张图片
LC207topologicalSort.png

我以前只会用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));
    }
}

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 
        }
        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));
    }
}

你可能感兴趣的:(lc207 course schedule )