summary:
construct graph | dfs graph for finding if cycle exist
package myapp.kit.leetcode.graph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Created with IDEA
* author:Dingsheng Huang
* Date:2020/4/15
* Time:上午10:56
*
* 207
* medium
* https://leetcode.com/problems/course-schedule/
*
* There are a total of numCourses courses you have to take, labeled from 0 to numCourses-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: numCourses = 2, prerequisites = [[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: numCourses = 2, prerequisites = [[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.
*
*
* Constraints:
*
* 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.
* 1 <= numCourses <= 10^5
*
*
*/
public class CourseSchedule {
// construct graph , dfs graph for find if circle exist
// optimize
public boolean canFinish2(int numCourses, int[][] prerequisites) {
if (prerequisites.length == 0) {
return true;
}
ArrayList<Integer>[] graph = new ArrayList[numCourses];
for (int i = 0; i < numCourses; i++) {
graph[i] = new ArrayList<>();
}
// pruning : using hash set filter unnecessary nodes
int cn = 0;
Set<Integer> set = new HashSet<>();
Set<Integer> setFrom = new HashSet<>();
for (int[] pair : prerequisites) {
graph[pair[0]].add(pair[1]);
if (!set.contains(pair[0])) {
cn++;
set.add(pair[0]);
setFrom.add(pair[0]);
}
if (!set.contains(pair[1])) {
cn++;
set.add(pair[1]);
}
}
for (int i : setFrom) {
if (!dfs(i, 1, cn, graph)) {
return false;
}
}
return true;
}
public boolean dfs(int curr, int depth, int n, ArrayList<Integer>[] graph) {
if (depth > n) {
return false;
}
for (int i : graph[curr]) {
if (!dfs(i, depth + 1, n, graph)) {
return false;
}
}
return true;
}
// original intuition when I encounter this problem :
private Map<Integer, Node> nodeMap = new HashMap<>();
// construct graph , dfs
public boolean canFinish(int numCourses, int[][] prerequisites) {
if (numCourses == 1 || prerequisites.length == 0) {
return true;
}
constructGraph(prerequisites);
for (Map.Entry<Integer, Node> entry : nodeMap.entrySet()) {
if (!dfsGraph(new HashSet<>(), entry.getValue())) {
return false;
}
}
return true;
}
private void constructGraph(int[][] pairs) {
for (int[] pair : pairs) {
Node nodeFrom = null;
if (nodeMap.containsKey(pair[0])) {
nodeFrom = nodeMap.get(pair[0]);
} else {
nodeFrom = new Node(pair[0]);
nodeMap.put(pair[0], nodeFrom);
}
Node nodeTo = null;
if (nodeMap.containsKey(pair[1])) {
nodeTo = nodeMap.get(pair[1]);
} else {
nodeTo = new Node(pair[1]);
nodeMap.put(pair[1], nodeTo);
}
nodeFrom.neighbors.add(nodeTo);
}
}
private boolean dfsGraph(Set<Node> visited, Node curr) {
if (visited.contains(curr)) {
return false;
}
visited.add(curr);
for (Node next : curr.neighbors) {
if (!dfsGraph(visited, next)) {
return false;
}
// back track
visited.remove(next);
}
return true;
}
private boolean dfsGraph2(int n, Node curr, int depth) {
if (depth > n) {
return false;
}
for (Node next : curr.neighbors) {
if (!dfsGraph2(n, next, depth + 1)) {
return false;
}
}
return true;
}
}