// https://leetcode.com/problems/course-schedule-ii // T: O(V + E) --> O(numCourses + |preReq|) // S: O(V + E) --> O(numCourses + |preReq|) import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.Set; public class CourseScheduleII { private static final class Vertex { private final int data; private final Set<Edge> edges = new HashSet<>(); private int outDegree = 0; Vertex(int data) { this.data = data; } private void addEdge(Edge edge) { edges.add(edge); if (edge.from == this) outDegree++; } private void removeEdge(Edge edge) { edges.remove(edge); if (edge.from == this) outDegree--; } private boolean hasDependency() { return outDegree > 0; } } private record Edge(Vertex from, Vertex to) { } public int[] findOrder(int numCourses, int[][] prerequisites) { final Map<Integer, Vertex> graph = createGraphWithNVertices(numCourses); mapPrerequisitesInGraph(graph, prerequisites); List<Integer> topologicalOrder = topologicalSort(graph); return topologicalOrder.size() == numCourses ? toArray(topologicalOrder) : new int[] { }; } private List<Integer> topologicalSort(Map<Integer, Vertex> graph) { final Queue<Vertex> queue = zeroDependencyVertices(graph); final List<Integer> order = new ArrayList<>(); while (!queue.isEmpty()) { Vertex vertex = queue.poll(); order.add(vertex.data); for (Edge edge : vertex.edges) { edge.from.removeEdge(edge); if (!edge.from.hasDependency()) { queue.add(edge.from); } } } return order; } private Queue<Vertex> zeroDependencyVertices(Map<Integer, Vertex> graph) { final Queue<Vertex> queue = new LinkedList<>(); for (Vertex vertex : graph.values()) { if (!vertex.hasDependency()) { queue.add(vertex); } } return queue; } private void mapPrerequisitesInGraph(Map<Integer, Vertex> graph, int[][] prerequisites) { for (int[] preRequisite : prerequisites) { Vertex from = graph.get(preRequisite[0]); Vertex to = graph.get(preRequisite[1]); Edge edge = new Edge(from, to); from.addEdge(edge); to.addEdge(edge); } } private Map<Integer, Vertex> createGraphWithNVertices(int n) { final Map<Integer, Vertex> graph = new HashMap<>(); for (int i = 0 ; i < n ; i++) { graph.put(i, new Vertex(i)); } return graph; } private int[] toArray(List<Integer> list) { final int[] array = new int[list.size()]; for (int i = 0 ; i < array.length ; i++) { array[i] = list.get(i); } return array; } }