Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using topological sort strategy.
There are a total of numCourses courses you have to take, labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you must take course ai first if you want to take course bi.
[0, 1] indicates that you have to take course 0 before you can take course 1.Prerequisites can also be indirect. If course a is a prerequisite of course b, and course b is a prerequisite of course c, then course a is a prerequisite of course c.
You are also given an array queries where queries[j] = [uj, vj]. For the jth query, you should answer whether course uj is a prerequisite of course vj or not.
Return a boolean array answer, where answer[j] is the answer to the jth query.
Example 1:
Input: numCourses = 2, prerequisites = [[1,0]], queries = [[0,1],[1,0]] Output: [false,true] Explanation: The pair [1, 0] indicates that you have to take course 1 before you can take course 0. Course 0 is not a prerequisite of course 1, but the opposite is true.
Example 2:
Input: numCourses = 2, prerequisites = [], queries = [[1,0],[0,1]] Output: [false,false] Explanation: There are no prerequisites, and each course is independent.
Example 3:
Input: numCourses = 3, prerequisites = [[1,2],[1,0],[2,0]], queries = [[1,0],[1,2]] Output: [true,true]
Constraints:
2 <= numCourses <= 1000 <= prerequisites.length <= (numCourses * (numCourses - 1) / 2)prerequisites[i].length == 20 <= ai, bi <= numCourses - 1ai != bi[ai, bi] are unique.1 <= queries.length <= 1040 <= ui, vi <= numCourses - 1ui != viProblem summary: There are a total of numCourses courses you have to take, labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you must take course ai first if you want to take course bi. For example, the pair [0, 1] indicates that you have to take course 0 before you can take course 1. Prerequisites can also be indirect. If course a is a prerequisite of course b, and course b is a prerequisite of course c, then course a is a prerequisite of course c. You are also given an array queries where queries[j] = [uj, vj]. For the jth query, you should answer whether course uj is a prerequisite of course vj or not. Return a boolean array answer, where answer[j] is the answer to the jth query.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Topological Sort
2 [[1,0]] [[0,1],[1,0]]
2 [] [[1,0],[0,1]]
3 [[1,2],[1,0],[2,0]] [[1,0],[1,2]]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1462: Course Schedule IV
class Solution {
public List<Boolean> checkIfPrerequisite(int n, int[][] prerequisites, int[][] queries) {
boolean[][] f = new boolean[n][n];
for (var p : prerequisites) {
f[p[0]][p[1]] = true;
}
for (int k = 0; k < n; ++k) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
f[i][j] |= f[i][k] && f[k][j];
}
}
}
List<Boolean> ans = new ArrayList<>();
for (var q : queries) {
ans.add(f[q[0]][q[1]]);
}
return ans;
}
}
// Accepted solution for LeetCode #1462: Course Schedule IV
func checkIfPrerequisite(n int, prerequisites [][]int, queries [][]int) (ans []bool) {
f := make([][]bool, n)
for i := range f {
f[i] = make([]bool, n)
}
for _, p := range prerequisites {
f[p[0]][p[1]] = true
}
for k := 0; k < n; k++ {
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
f[i][j] = f[i][j] || (f[i][k] && f[k][j])
}
}
}
for _, q := range queries {
ans = append(ans, f[q[0]][q[1]])
}
return
}
# Accepted solution for LeetCode #1462: Course Schedule IV
class Solution:
def checkIfPrerequisite(
self, n: int, prerequisites: List[List[int]], queries: List[List[int]]
) -> List[bool]:
f = [[False] * n for _ in range(n)]
for a, b in prerequisites:
f[a][b] = True
for k in range(n):
for i in range(n):
for j in range(n):
if f[i][k] and f[k][j]:
f[i][j] = True
return [f[a][b] for a, b in queries]
// Accepted solution for LeetCode #1462: Course Schedule IV
struct Solution;
use std::collections::HashSet;
impl Solution {
fn check_if_prerequisite(
n: i32,
prerequisites: Vec<Vec<i32>>,
queries: Vec<Vec<i32>>,
) -> Vec<bool> {
let n = n as usize;
let mut graph: Vec<HashSet<usize>> = vec![HashSet::new(); n];
for edge in prerequisites {
let u = edge[0] as usize;
let v = edge[1] as usize;
graph[u].insert(v);
}
let mut closures: Vec<HashSet<usize>> = vec![HashSet::new(); n];
for i in 0..n {
let mut visited = vec![false; n];
Self::dfs(i, &mut visited, &mut closures, &graph, i);
}
queries
.into_iter()
.map(|v| closures[v[0] as usize].contains(&(v[1] as usize)))
.collect()
}
fn dfs(
u: usize,
visited: &mut Vec<bool>,
closures: &mut Vec<HashSet<usize>>,
graph: &[HashSet<usize>],
start: usize,
) {
if !visited[u] {
visited[u] = true;
for &v in &graph[u] {
closures[start].insert(v);
Self::dfs(v, visited, closures, graph, start);
}
}
}
}
#[test]
fn test() {
let n = 2;
let prerequisites = vec_vec_i32![[1, 0]];
let queries = vec_vec_i32![[0, 1], [1, 0]];
let res = vec![false, true];
assert_eq!(
Solution::check_if_prerequisite(n, prerequisites, queries),
res
);
let n = 2;
let prerequisites = vec_vec_i32![];
let queries = vec_vec_i32![[1, 0], [0, 1]];
let res = vec![false, false];
assert_eq!(
Solution::check_if_prerequisite(n, prerequisites, queries),
res
);
let n = 3;
let prerequisites = vec_vec_i32![[1, 2], [1, 0], [2, 0]];
let queries = vec_vec_i32![[1, 0], [1, 2]];
let res = vec![true, true];
assert_eq!(
Solution::check_if_prerequisite(n, prerequisites, queries),
res
);
let n = 3;
let prerequisites = vec_vec_i32![[1, 0], [2, 0]];
let queries = vec_vec_i32![[0, 1], [2, 0]];
let res = vec![false, true];
assert_eq!(
Solution::check_if_prerequisite(n, prerequisites, queries),
res
);
let n = 5;
let prerequisites = vec_vec_i32![[0, 1], [1, 2], [2, 3], [3, 4]];
let queries = vec_vec_i32![[0, 4], [4, 0], [1, 3], [3, 0]];
let res = vec![true, false, true, false];
assert_eq!(
Solution::check_if_prerequisite(n, prerequisites, queries),
res
);
}
// Accepted solution for LeetCode #1462: Course Schedule IV
function checkIfPrerequisite(n: number, prerequisites: number[][], queries: number[][]): boolean[] {
const f = Array.from({ length: n }, () => Array(n).fill(false));
prerequisites.forEach(([a, b]) => (f[a][b] = true));
for (let k = 0; k < n; ++k) {
for (let i = 0; i < n; ++i) {
for (let j = 0; j < n; ++j) {
f[i][j] ||= f[i][k] && f[k][j];
}
}
}
return queries.map(([a, b]) => f[a][b]);
}
Use this to step through a reusable interview workflow for this problem.
Repeatedly find a vertex with no incoming edges, remove it and its outgoing edges, and repeat. Finding the zero-in-degree vertex scans all V vertices, and we do this V times. Removing edges touches E edges total. Without an in-degree array, this gives O(V × E).
Build an adjacency list (O(V + E)), then either do Kahn's BFS (process each vertex once + each edge once) or DFS (visit each vertex once + each edge once). Both are O(V + E). Space includes the adjacency list (O(V + E)) plus the in-degree array or visited set (O(V)).
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.