[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?
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.
Hints:
Time complexity:
Building graph and in-degrees takes O(E). Topological sort takes O(V + E). The overall time complexity is O(V + E).
Solution 2 (DFS):
- This problem is equivalent to finding if a cycle exists in a directed graph. If a cycle exists, no topological ordering exists and therefore it will be impossible to take all courses.
- Topological Sort via DFS - A great video tutorial (21 minutes) on Coursera explaining the basic concepts of Topological Sort.
- Topological sort could also be done via BFS.
Thought process:
Topological sort:
- Build graph:
- Use a hash map of int -> set of int to represent graph. The key of the map is a course, the value is a set of courses which have the key course as a prerequisite.
- Use another hash map of int -> int to keep track of the in-degrees of each course.
- Iterate through the edge list. Populate the graph and the in-degree map.
- Sort:
- Iterate through the in-degrees. Offer courses with no prerequisites to a queue.
- Topological sort. Keep track of courses polled from queue.
- If the number of sorted courses equals total number of courses, there is no circular dependency. So it's possible to finish all courses and vice versa.
Solution 1 (BFS):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | public class Solution { public boolean canFinish(int numCourses, int[][] prerequisites) { Map<Integer, Set<Integer>> graph = new HashMap<>(); Map<Integer, Integer> indegrees = new HashMap<>(); for (int[] edge : prerequisites) { Set<Integer> uppers = graph.getOrDefault(edge[1], new HashSet<>()); uppers.add(edge[0]); graph.put(edge[1], uppers); int indegree = indegrees.getOrDefault(edge[0], 0); indegree++; indegrees.put(edge[0], indegree); indegrees.put(edge[1], indegrees.getOrDefault(edge[1], 0)); } Queue<Integer> queue = new LinkedList<>(); for (int course : indegrees.keySet()) { if (indegrees.get(course) == 0) { queue.offer(course); } } int sorted = 0; while (!queue.isEmpty()) { int course = queue.poll(); sorted++; if (graph.containsKey(course)) { for (int upper : graph.get(course)) { int indegree = indegrees.get(upper) - 1; indegrees.put(upper, indegree); if (indegree == 0) { queue.offer(upper); } } } } return sorted == indegrees.size(); } } |
Time complexity:
Building graph and in-degrees takes O(E). Topological sort takes O(V + E). The overall time complexity is O(V + E).
Solution 2 (DFS):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | class Solution { public boolean canFinish(int numCourses, int[][] prerequisites) { Map<Integer, Set<Integer>> graph = new HashMap<>(); for (int i = 0; i < numCourses; i++) { graph.put(i, new HashSet<>()); } for (int[] edge : prerequisites) { graph.get(edge[1]).add(edge[0]); } boolean[] visited = new boolean[numCourses]; for (int i = 0; i < numCourses; i++) { if (hasCycle(i, graph, new boolean[numCourses], visited)) { return false; } } return true; } private boolean hasCycle(int course, Map<Integer, Set<Integer>> graph, boolean[] onPath, boolean[] visited) { if (onPath[course]) { return true; } onPath[course] = true; for (int neighbor : graph.get(course)) { if (!visited[neighbor] && hasCycle(neighbor, graph, onPath, visited)) { return true; } } visited[course] = true; return false; } } |
Comments
Post a Comment