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?

For example:
2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
2, [[1,0],[0,1]]
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.

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

Topological Sort: http://www.reibang.com/p/5880cf3be264

Solution1:Topological sort from Indegree==0 (by BFS)

思路:從indegree==0的地方bfs向內(nèi)部找奈泪,找到將該node剪掉(其置為visited或?qū)⑵鋓ndegree無效 并 更新其neighbors的indegree--),然后繼續(xù)從indegree==0的地方找鞭铆。當找不到的時候退出娜膘,看是否遍歷了全部N個結(jié)點嘀粱。
(queue也可以該成stack, 但整體思路是BFS的,內(nèi)部小部分dfs/bfs都可以)
(不用queue起始也可以的,hashmap記錄indegree==0的標號岛都,或是每次再搜索別的indegree==0的結(jié)點风瘦,整體思路是BFS的)
BFS uses the indegrees of each node. We will first try to find a node with 0 indegree. If we fail to do so, there must be a cycle in the graph and we return false. Otherwise we have found one. We set its reduce the indegrees of all its neighbors by 1. This process should be repeated for n (number of nodes) times. If not, we return false, otherwise we will return true.
實現(xiàn)1a: 鄰接矩陣
Time Complexity: O(V ^ 2) Space Complexity: O(V ^ 2)
實現(xiàn)1b: 鄰接表 (recommended)
Time Complexity: O(V + E) Space Complexity: O(V + E)

Solution2:Topological sort (DFS) 看是否onpath上有cycle

思路:任意起始dfs向深找队魏,過程記錄global visited,global visited的說明已經(jīng)dfs過了不用處理万搔,并keep一個on_path的visited胡桨,就是一次dfs到底過程中的on_path visited,如果碰到on_path visited 說明有l(wèi)oop不能夠完成Topological Sort瞬雹。on_path visited的更新類似回溯昧谊,到底后回溯回來一步要將該結(jié)點的on_path visited再改為false.

If it meets a node which was visited in the current process of DFS visit, a cycle is detected and we will return false. Otherwise it will start from another unvisited node and repeat this process till all the nodes have been visited. Note that you should make two records: one is to record all the visited nodes and the other is to record the visited nodes in the current DFS visit.

這里實現(xiàn)用了 鄰接表
Time Complexity: O(V + E) Space Complexity: O(V + E) 遞歸緩存

Solution1a Code:

class Solution {
   public boolean canFinish(int numCourses, int[][] prerequisites) {
        int[][] matrix = new int[numCourses][numCourses]; // i -> j
        int[] indegree = new int[numCourses];

        // graph build
        for (int i = 0; i < prerequisites.length; i++) {
            int pre = prerequisites[i][1];
            int post = prerequisites[i][0];
            indegree[post]++; 
            matrix[pre][post] = 1;
        }

        // bfs from nodes whose degree == 0
        int count = 0;
        Queue<Integer> queue = new LinkedList();
        for (int i = 0; i < indegree.length; i++) {
            if (indegree[i] == 0) queue.offer(i);
        }
        while (!queue.isEmpty()) {
            int course = queue.poll();
            count++;
            for (int i = 0; i < numCourses; i++) {
                if (matrix[course][i] != 0) {
                    if (--indegree[i] == 0)
                        queue.offer(i);
                }
            }
        }
        return count == numCourses;
    }
}

Solution1b Code:

class Solution {
   public boolean canFinish(int numCourses, int[][] prerequisites) {
        int[] indegree = new int[numCourses];
        // O(V + E)
        // graph build
        // graph = adj_list init
        List<List<Integer>> graph = new ArrayList<List<Integer>>();
        for(int i = 0; i < numCourses; i++) {
            graph.add(new ArrayList<Integer>()); // LinkedList is also OK
        }
       // O(E) part
        for (int i = 0; i < prerequisites.length; i++) {
            int pre = prerequisites[i][1];
            int post = prerequisites[i][0];
            indegree[post]++; 
            graph.get(pre).add(post);
        }
        // O(V) part
        // bfs from nodes whose degree == 0
        int count = 0;
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < indegree.length; i++) {
            if (indegree[i] == 0) queue.offer(i);
        }
        while (!queue.isEmpty()) {
            int course = queue.poll();
            count++;
            List<Integer> next_list = graph.get(course);
            for(int i = 0; i < next_list.size(); i++) {
                if (--indegree[next_list.get(i)] == 0) {
                    queue.offer(next_list.get(i));
                }
            }
           
        }
        return count == numCourses;
    }
}

Solution2 Code:

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        // O(V + E)
        // graph = adj_list init
        List<List<Integer>> graph = new ArrayList<List<Integer>>();
        for(int i = 0; i < numCourses; i++) {
            graph.add(new ArrayList<Integer>()); // LinkedList is also OK
        }
        
        boolean[] visited = new boolean[numCourses];
        boolean[] onpath = new boolean[numCourses];
        // O(E) part
        // graph(adj_list) build
        for (int i = 0; i < prerequisites.length; i++) {
            int pre = prerequisites[i][1];
            int post = prerequisites[i][0];
            graph.get(pre).add(post);
        }
       // O(V) part
        for(int i = 0; i < numCourses; i++) {
            if(!visited[i] && dfs_cycle(graph, i, visited, onpath)) {
                return false;
            }
        }
                
        return true;
    }
    
    // dfs to detect cycle by using onpath, if detected: return true;
    private boolean dfs_cycle(List<List<Integer>> graph, int node, boolean[] visited, boolean[] onpath) {

        onpath[node] = true;
        visited[node] = true; 
        
        for(int i = 0; i < graph.get(node).size(); i++) {
            int neighbor = graph.get(node).get(i);
            if (onpath[neighbor] || (!visited[neighbor] && dfs_cycle(graph, neighbor, visited, onpath))) {
                return true;
            }
        }
        // onpath step back
        onpath[node] = false;
        
        return false;       
    }
}

Solution2.round1 Code:

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        if(numCourses == 0 || prerequisites == null || prerequisites.length == 0) return true;
        
        // graph define
        List<List<Integer>> graph = new ArrayList<>();
        for(int i = 0; i < numCourses; i++) {
            graph.add(new ArrayList<>());
        }
        
        // graph build
        for(int i = 0; i < prerequisites.length; i++) {
            graph.get(prerequisites[i][1]).add(prerequisites[i][0]);
        }
        
        boolean[] g_visited = new boolean[numCourses];
        boolean[] on_path = new boolean[numCourses];
        
        
        for(int i = 0; i < numCourses; i++) {
            if(!g_visited[i] && dfsDetectCycle(graph, i, g_visited, on_path)) {
                return false;
            }
        }
        
        return true;
        
        
    }
    
    private boolean dfsDetectCycle(List<List<Integer>> graph, int cur, boolean[] g_visited, boolean[] on_path) {
        
        g_visited[cur] = true;
        on_path[cur] = true;
        
        List<Integer> neighbors = graph.get(cur);
        for(Integer neighbor: neighbors) {
            if(on_path[neighbor]) {
                return true;
            }
            
            if(g_visited[neighbor]) continue;
            if(dfsDetectCycle(graph, neighbor, g_visited, on_path)) {
                return true;
            }
        }
        on_path[cur] = false;
        
        return false;
    }
}

Tag_Round1 Code

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        
        if(numCourses == 0 || prerequisites == null || prerequisites.length == 0) return true;
        
        // build graph
        List<List<Integer>> graph = new ArrayList<>();
        for(int i = 0; i< numCourses; i++) {
            graph.add(new ArrayList<>());
        }
        
        // init graph 
        for(int i = 0; i < prerequisites.length; i++) {
            int pre = prerequisites[i][1];
            int post = prerequisites[i][0];
            graph.get(pre).add(post);
        }
        
        boolean[] g_visited = new boolean[numCourses];
        boolean[] on_path = new boolean[numCourses];
        
        // dfs detect cycle
        for(int i = 0; i < graph.size(); i++) {
            if(g_visited[i] || graph.get(i).size() == 0) continue;
            if(dfsCycle(graph, i, g_visited, on_path)) {
                return false;
            }
        }
        return true;
        
    }
    
    private boolean dfsCycle(List<List<Integer>> graph, int start_id, boolean[] g_visited, boolean[] on_path) {
        g_visited[start_id] = true;
        on_path[start_id] = true;
        
        List<Integer> next_list = graph.get(start_id);
        for(int i = 0; i < next_list.size(); i++) {
            int next = next_list.get(i);
            if(on_path[next]) return true;
            if(g_visited[next]) continue;
            if(dfsCycle(graph, next, g_visited, on_path)) return true;
         
        }
        on_path[start_id] = false;
        return false;
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市酗捌,隨后出現(xiàn)的幾起案子呢诬,更是在濱河造成了極大的恐慌涌哲,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尚镰,死亡現(xiàn)場離奇詭異阀圾,居然都是意外死亡,警方通過查閱死者的電腦和手機狗唉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門初烘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人敞曹,你說我怎么就攤上這事账月。” “怎么了澳迫?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵局齿,是天一觀的道長。 經(jīng)常有香客問我橄登,道長抓歼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任拢锹,我火速辦了婚禮谣妻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘卒稳。我一直安慰自己蹋半,他們只是感情好,可當我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布充坑。 她就那樣靜靜地躺著减江,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捻爷。 梳的紋絲不亂的頭發(fā)上辈灼,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天,我揣著相機與錄音也榄,去河邊找鬼巡莹。 笑死,一個胖子當著我的面吹牛甜紫,可吹牛的內(nèi)容都是我干的降宅。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼囚霸,長吁一口氣:“原來是場噩夢啊……” “哼腰根!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起邮辽,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤唠雕,失蹤者是張志新(化名)和其女友劉穎贸营,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岩睁,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡钞脂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捕儒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冰啃。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖刘莹,靈堂內(nèi)的尸體忽然破棺而出阎毅,到底是詐尸還是另有隱情,我是刑警寧澤点弯,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布扇调,位于F島的核電站,受9級特大地震影響抢肛,放射性物質(zhì)發(fā)生泄漏狼钮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一捡絮、第九天 我趴在偏房一處隱蔽的房頂上張望熬芜。 院中可真熱鬧,春花似錦福稳、人聲如沸涎拉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鼓拧。三九已至,卻和暖如春略板,著一層夾襖步出監(jiān)牢的瞬間毁枯,已是汗流浹背慈缔。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工叮称, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人藐鹤。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓瓤檐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親娱节。 傳聞我的和親對象是個殘疾皇子挠蛉,可洞房花燭夜當晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內(nèi)容