Related Problem: 210. Course Schedule II.

DFS on Directed Graph:

var canFinish = function (numCourses, prerequisites) {
	const n = numCourses,
		adjList = buildGraph(n, prerequisites),
		// parent = new Array(n).fill(-1),
		visited = new Array(n).fill(-1),
		arrival = new Array(n).fill(-1),
		departure = new Array(n).fill(-1)

	let timestamp = 0
	// let components = 0 // This makes no sense in a directed graph

	for (let v = 0; v < n; v++) {
		if (visited[v] === -1) {
			// components++
			// if (components > 1) return false

			// if cycle found, you cannot complete the courses
			if (dfs(v)) return false
		}
	}

	return true // no cycle found anywhere

	// -----------------------------------------------
	function dfs(source) {
		arrival[source] = timestamp
		timestamp++
		visited[source] = 1

		for (const neighbor of adjList[source]) {
			if (visited[neighbor] === -1) {
				// parent[neighbor] = source
				if (dfs(neighbor)) return true
			} else {
				// This is a back edge, hence a cycle
				if (departure[neighbor] === -1) return true
			}
		}

		departure[source] = timestamp
		timestamp++
		return false
	}
	// -----------------------------------------------
	function buildGraph(n, edges) {
		const adjList = new Array(n).fill().map(() => [])

		for (const [src, dest] of edges) {
			// directed graph so push one direction only
			// adjList[src].push(dest)
			adjList[dest].push(src)
		}

		return adjList
	}
}

// tests
console.log(
	canFinish(2, [
		[1, 0],
		[0, 1],
	])
)
console.log(
	canFinish(6, [
		[1, 0],
		[2, 1],
		[3, 1],
		[4, 3],
		[3, 0],
		// [0, 2],
		[2, 4],
		[3, 5],
		[0, 5],
	])
)