Course Schedule II:判断有向图是否有环

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, return the ordering of courses you should take to finish all courses.

There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.

Example 1:

Input: 2, [[1,0]] 
Output: [0,1]
Explanation: There are a total of 2 courses to take. To take course 1 you should have finished   
             course 0. So the correct course order is [0,1] .

Example 2:

Input: 4, [[1,0],[2,0],[3,1],[3,2]]
Output: [0,1,2,3] or [0,2,1,3]
Explanation: There are a total of 4 courses to take. To take course 3 you should have finished both     
             courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. 
             So one correct course order is [0,1,2,3]. Another correct ordering is [0,2,1,3] .

Note:

  1. The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
  2. You may assume that there are no duplicate edges in the input prerequisites.

思路1:判断每个顶点的入度,每次将入度为0的顶点移除,直至所有顶点均被移除,否则图有环。

思路2:深度优先遍历每个顶点,若访问期间再次访问到正在被当前遍历访问中的顶点,则图有环。visited表示是否正在被访问,discover表示该顶点是否已被深度优先遍历过。(相当于用三种颜色表示节点:未被访问、正在被访问、已经访问完毕三种状态。)

思路二代码:来自:https://leetcode.com/problems/course-schedule-ii/discuss/133808/Java-DFS-beats-99.

class Solution {
    
    boolean[] discovered;
    boolean[] visited;
    int[] resultSet;
    int counter=0;
    
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        
        // Construct adjList first
        List<Integer>[] adjList = constructAdjList(numCourses, prerequisites);
       
        discovered = new boolean[numCourses];
        visited = new boolean[numCourses];
        
        resultSet = new int[numCourses];
        
        for(int i=0; i<numCourses; i++) {
            
            if(!discovered[i]) {
                
                if(adjList[i] == null){
                    discovered[i] = true;
                    resultSet[counter++] = i; // Courses which don't have any prereq can be added in any order.
                    continue;
                }
                
                if(findCycle(i, adjList)) {
                    return new int[0];
                }
                
            }
            
        }
        
        return resultSet;
        
    }
    
    private List<Integer>[] constructAdjList(int n, int[][] prereq) {
        
        List<Integer>[] adjList = new ArrayList[n];
        
        for(int i=0; i<prereq.length; i++) {
            
            int vertex = prereq[i][0];
            int neighbor = prereq[i][1];
            
            if(adjList[vertex] == null) {
                adjList[vertex] = new ArrayList<Integer>();
            }
            
            adjList[vertex].add(neighbor);
            
        }
        
        return adjList;
        
    }
    
    private boolean findCycle(int vertex, List<Integer>[] adjList) {
        
        discovered[vertex] = true;
        visited[vertex] = true;
        
        boolean result = false;
        List<Integer> neighbors = adjList[vertex];
        
        if(neighbors!=null) {  // Important as we are constructing adjList only for vertices available in prerequisites array.
            for(Integer neighbor: neighbors) {

                if(visited[neighbor]) { // back-edge found!
                    result = true;
                    break;
                }

                if(discovered[neighbor]) { // If already discovered, no need to traverse again. Consider other neighbors!
                    continue;
                }

                if(findCycle(neighbor, adjList)) { // Perform DFS.
                    result = true;
                    break;
                }

            }
        }
        
        resultSet[counter++] = vertex; // Add the course to resultSet
        visited[vertex] = false;  // Very important line to find back-edge.
        return result;
        
    }
}

思路一代码是我自己写的,击败了2%的选手,难过

class Solution {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        //if(prerequisites == null) return null;
        int m = prerequisites.length;
        //if(m <= 0) return null;
        Map<Integer,Set<Integer>> in = new HashMap<Integer,Set<Integer>>();
        Map<Integer,Set<Integer>> out = new HashMap<Integer,Set<Integer>>();
        for(int i = 0 ; i < numCourses ; i++){
            in.put(i,new HashSet<Integer>());
            out.put(i,new HashSet<Integer>());
        }
        for(int i = 0 ; i < m ; i++){            
            in.get(prerequisites[i][0]).add(prerequisites[i][1]);
            out.get(prerequisites[i][1]).add(prerequisites[i][0]);
        }
        List<Integer> ans = new ArrayList<Integer>();
        Set<Integer> temp = new HashSet<Integer>();
        while(true){
            int start = -1;
            for(int i = 0 ; i < numCourses ; i++){
                if(in.get(i).size() == 0 && !temp.contains(i)){
                    start = i;
                    break;
                }
            }
            if(start == -1){
                if(ans.size() == numCourses) {
                    int[] res = new int[numCourses];
                    for(int i = 0 ; i < numCourses;i++){
                        res[i] = ans.get(i);
                    }
                    return res;
                }else{
                     return new int[0];
                }            
            }else{
                ans.add(start); 
                temp.add(start);
                for(int i : out.get(start)){
                    in.get(i).remove(start);
                }            
            }
        }
    }
}


猜你喜欢

转载自blog.csdn.net/u013300579/article/details/80589829