LeetCode : 207. Course Schedule 課程先後順序規劃

試題
There are a total of n courses you have to take, labeled from 0 to n-1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?

Example 1:

Input: 2, [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.
Example 2:

Input: 2, [[1,0],[0,1]]
Output: false
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0, and to take course 0 you should
also have finished course 1. So it is impossible.

代碼
有以下思路:
1、對於沒有入度出度的節點可以直接完成,對於沒有入度的節點也可以直接完成。
2、有入度的節點必須要依賴的節點都完成了,才能夠完成。我們可以統計每個節點的依賴完成數量。
3、使用寬度優先,先完成1中節點,然後當2中節點的依賴完成後才能完成。

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        if(prerequisites.length == 0) return true;
        
        
        HashSet<Integer> start = new HashSet<>();
        HashMap<Integer, ArrayList<Integer>> graph = new HashMap<>();
        Stack<Integer> stack = new Stack<>();
        int[] sum = new int[numCourses];
        
        for(int i = 0; i < numCourses; i++){
            start.add(i);
        }
        for(int[] e : prerequisites){
            sum[e[1]]++;
            if(start.contains(e[1])){
                start.remove(e[1]);
            }
            if(graph.containsKey(e[0])){
                graph.get(e[0]).add(e[1]);
            }else{
                ArrayList<Integer> temp = new ArrayList<>();
                temp.add(e[1]);
                graph.put(e[0], temp);
            }
        }
        
        if(start.size() == 0){
            return false;
        }
        for(int s : start){
            stack.push(s);
        }
        int count = 0;
        
        while(!stack.isEmpty()){
            int size = stack.size();
            for(int i = 0; i < size; i++){
                int cur = stack.pop();
                count++;
                
                if(graph.containsKey(cur)){
                    ArrayList<Integer> nxt = graph.get(cur);
                    for(int n : nxt){
                        sum[n]--;
                        if(sum[n] == 0){
                            stack.push(n);
                        }
                    }   
                }    
            }
        }
        
        if(count == numCourses){
            return true;
        }
        return false;
        
    }
}

另外其實這題有個特點是如果無法完成,那麼說明圖中存在一個環。所以可快速判斷圖中是否有環。

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        if (numCourses == 0 || prerequisites == null || prerequisites.length == 0) return true; // ??
        
        // Index of this list is a course and its values are the dependencies (children)
        List<List<Integer>> courseDependency = new ArrayList<>(numCourses);
        
        for (int i = 0; i < numCourses; i++)
            courseDependency.add(new ArrayList<>());
        
        /*
        create following courseDependency arraylist for each index (course)
            0: [1,2],
            1: [2],
            2: []
        */
        for (int i = 0; i < prerequisites.length; i++) {
            courseDependency.get(prerequisites[i][0]).add(prerequisites[i][1]);
        }

        // use state int array to represent current status of visiting for each node
		// 0: not visited yet, 1: currently visiting (in recursion stack frame), 2: already visited
        int[] state = new int[numCourses];
        
        for (int i = 0; i < numCourses; i++) {
            if (!dfs(i, courseDependency, state)) {
                return false;   // Cycle found
            }
        }
        
        // no cycle found
        return true;
    }
    
    private boolean dfs(int course, List<List<Integer>> courseDependency, int[] state) {
        
        state[course] = 1;  // currently visiting
        
        List<Integer> dependencies = courseDependency.get(course);
        
        for (int children: dependencies) {
            if (state[children] == 1)   // If any children is also being currently visiting, then cycle is detected
                return false;
            
            if (state[children] == 0) { // Not visted yet
                if (!dfs(children, courseDependency, state))
                    return false;
            }
        }
        
        state[course] = 2;  // done visiting
        return true;        // no cycle, backtrack to caller
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章