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 core interview patterns strategy.
You are given an integer n and a directed graph with n nodes labeled from 0 to n - 1. This is represented by a 2D array edges, where edges[i] = [ui, vi, starti, endi] indicates an edge from node ui to vi that can only be used at any integer time t such that starti <= t <= endi.
You start at node 0 at time 0.
In one unit of time, you can either:
t satisfies starti <= t <= endi.Return the minimum time required to reach node n - 1. If it is impossible, return -1.
Example 1:
Input: n = 3, edges = [[0,1,0,1],[1,2,2,5]]
Output: 3
Explanation:
The optimal path is:
t = 0, take the edge (0 → 1) which is available from 0 to 1. You arrive at node 1 at time t = 1, then wait until t = 2.t = 2, take the edge (1 → 2) which is available from 2 to 5. You arrive at node 2 at time 3.Hence, the minimum time to reach node 2 is 3.
Example 2:
Input: n = 4, edges = [[0,1,0,3],[1,3,7,8],[0,2,1,5],[2,3,4,7]]
Output: 5
Explanation:
The optimal path is:
t = 1, then take the edge (0 → 2) which is available from 1 to 5. You arrive at node 2 at t = 2.t = 4, then take the edge (2 → 3) which is available from 4 to 7. You arrive at node 3 at t = 5.Hence, the minimum time to reach node 3 is 5.
Example 3:
Input: n = 3, edges = [[1,0,1,3],[1,2,3,5]]
Output: -1
Explanation:
Constraints:
1 <= n <= 1050 <= edges.length <= 105edges[i] == [ui, vi, starti, endi]0 <= ui, vi <= n - 1ui != vi0 <= starti <= endi <= 109Problem summary: You are given an integer n and a directed graph with n nodes labeled from 0 to n - 1. This is represented by a 2D array edges, where edges[i] = [ui, vi, starti, endi] indicates an edge from node ui to vi that can only be used at any integer time t such that starti <= t <= endi. You start at node 0 at time 0. In one unit of time, you can either: Wait at your current node without moving, or Travel along an outgoing edge from your current node if the current time t satisfies starti <= t <= endi. Return the minimum time required to reach node n - 1. If it is impossible, return -1.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: General problem-solving
3 [[0,1,0,1],[1,2,2,5]]
4 [[0,1,0,3],[1,3,7,8],[0,2,1,5],[2,3,4,7]]
3 [[1,0,1,3],[1,2,3,5]]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3604: Minimum Time to Reach Destination in Directed Graph
// Auto-generated Java example from go.
class Solution {
public void exampleSolution() {
}
}
// Reference (go):
// // Accepted solution for LeetCode #3604: Minimum Time to Reach Destination in Directed Graph
// package main
//
// import (
// "container/heap"
// "math"
// )
//
// // https://space.bilibili.com/206214
// func minTime(n int, edges [][]int) int {
// type edge struct{ to, start, end int }
// g := make([][]edge, n)
// for _, e := range edges {
// x, y := e[0], e[1]
// g[x] = append(g[x], edge{y, e[2], e[3]})
// }
//
// dis := make([]int, n)
// for i := range dis {
// dis[i] = math.MaxInt
// }
// dis[0] = 0
// h := hp{{}}
// for len(h) > 0 {
// p := heap.Pop(&h).(pair)
// d := p.d
// x := p.x
// if d > dis[x] {
// continue
// }
// if x == n-1 {
// return d
// }
// for _, e := range g[x] {
// y := e.to
// newD := max(d, e.start) + 1
// if newD-1 <= e.end && newD < dis[y] {
// dis[y] = newD
// heap.Push(&h, pair{newD, y})
// }
// }
// }
// return -1
// }
//
// type pair struct{ d, x int }
// type hp []pair
// func (h hp) Len() int { return len(h) }
// func (h hp) Less(i, j int) bool { return h[i].d < h[j].d }
// func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
// func (h *hp) Push(v any) { *h = append(*h, v.(pair)) }
// func (h *hp) Pop() (v any) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }
// Accepted solution for LeetCode #3604: Minimum Time to Reach Destination in Directed Graph
package main
import (
"container/heap"
"math"
)
// https://space.bilibili.com/206214
func minTime(n int, edges [][]int) int {
type edge struct{ to, start, end int }
g := make([][]edge, n)
for _, e := range edges {
x, y := e[0], e[1]
g[x] = append(g[x], edge{y, e[2], e[3]})
}
dis := make([]int, n)
for i := range dis {
dis[i] = math.MaxInt
}
dis[0] = 0
h := hp{{}}
for len(h) > 0 {
p := heap.Pop(&h).(pair)
d := p.d
x := p.x
if d > dis[x] {
continue
}
if x == n-1 {
return d
}
for _, e := range g[x] {
y := e.to
newD := max(d, e.start) + 1
if newD-1 <= e.end && newD < dis[y] {
dis[y] = newD
heap.Push(&h, pair{newD, y})
}
}
}
return -1
}
type pair struct{ d, x int }
type hp []pair
func (h hp) Len() int { return len(h) }
func (h hp) Less(i, j int) bool { return h[i].d < h[j].d }
func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v any) { *h = append(*h, v.(pair)) }
func (h *hp) Pop() (v any) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }
# Accepted solution for LeetCode #3604: Minimum Time to Reach Destination in Directed Graph
#
# @lc app=leetcode id=3604 lang=python3
#
# [3604] Minimum Time to Reach Destination in Directed Graph
#
# @lc code=start
import heapq
class Solution:
def minTime(self, n: int, edges: List[List[int]]) -> int:
# Adjacency list to store graph: u -> [(v, start, end)]
graph = [[] for _ in range(n)]
for u, v, start, end in edges:
graph[u].append((v, start, end))
# Priority queue for Dijkstra: (current_time, node)
pq = [(0, 0)]
# Min time to reach each node, initialized to infinity
min_arrival = [float('inf')] * n
min_arrival[0] = 0
while pq:
curr_time, u = heapq.heappop(pq)
# If we reached the destination, return the time
if u == n - 1:
return curr_time
# If we found a faster way to u already, skip
if curr_time > min_arrival[u]:
continue
for v, start, end in graph[u]:
# Calculate the earliest time we can take this edge
# We must wait until at least 'start'.
# If we arrive after 'start', we can take it immediately (wait time = 0).
departure_time = max(curr_time, start)
# Check if the departure time is within the valid window [start, end]
if departure_time <= end:
arrival_time = departure_time + 1
# If this path is faster than any previous path to v
if arrival_time < min_arrival[v]:
min_arrival[v] = arrival_time
heapq.heappush(pq, (arrival_time, v))
return -1
# @lc code=end
// Accepted solution for LeetCode #3604: Minimum Time to Reach Destination in Directed Graph
// Rust example auto-generated from go reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (go):
// // Accepted solution for LeetCode #3604: Minimum Time to Reach Destination in Directed Graph
// package main
//
// import (
// "container/heap"
// "math"
// )
//
// // https://space.bilibili.com/206214
// func minTime(n int, edges [][]int) int {
// type edge struct{ to, start, end int }
// g := make([][]edge, n)
// for _, e := range edges {
// x, y := e[0], e[1]
// g[x] = append(g[x], edge{y, e[2], e[3]})
// }
//
// dis := make([]int, n)
// for i := range dis {
// dis[i] = math.MaxInt
// }
// dis[0] = 0
// h := hp{{}}
// for len(h) > 0 {
// p := heap.Pop(&h).(pair)
// d := p.d
// x := p.x
// if d > dis[x] {
// continue
// }
// if x == n-1 {
// return d
// }
// for _, e := range g[x] {
// y := e.to
// newD := max(d, e.start) + 1
// if newD-1 <= e.end && newD < dis[y] {
// dis[y] = newD
// heap.Push(&h, pair{newD, y})
// }
// }
// }
// return -1
// }
//
// type pair struct{ d, x int }
// type hp []pair
// func (h hp) Len() int { return len(h) }
// func (h hp) Less(i, j int) bool { return h[i].d < h[j].d }
// func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
// func (h *hp) Push(v any) { *h = append(*h, v.(pair)) }
// func (h *hp) Pop() (v any) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }
// Accepted solution for LeetCode #3604: Minimum Time to Reach Destination in Directed Graph
// Auto-generated TypeScript example from go.
function exampleSolution(): void {
}
// Reference (go):
// // Accepted solution for LeetCode #3604: Minimum Time to Reach Destination in Directed Graph
// package main
//
// import (
// "container/heap"
// "math"
// )
//
// // https://space.bilibili.com/206214
// func minTime(n int, edges [][]int) int {
// type edge struct{ to, start, end int }
// g := make([][]edge, n)
// for _, e := range edges {
// x, y := e[0], e[1]
// g[x] = append(g[x], edge{y, e[2], e[3]})
// }
//
// dis := make([]int, n)
// for i := range dis {
// dis[i] = math.MaxInt
// }
// dis[0] = 0
// h := hp{{}}
// for len(h) > 0 {
// p := heap.Pop(&h).(pair)
// d := p.d
// x := p.x
// if d > dis[x] {
// continue
// }
// if x == n-1 {
// return d
// }
// for _, e := range g[x] {
// y := e.to
// newD := max(d, e.start) + 1
// if newD-1 <= e.end && newD < dis[y] {
// dis[y] = newD
// heap.Push(&h, pair{newD, y})
// }
// }
// }
// return -1
// }
//
// type pair struct{ d, x int }
// type hp []pair
// func (h hp) Len() int { return len(h) }
// func (h hp) Less(i, j int) bool { return h[i].d < h[j].d }
// func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
// func (h *hp) Push(v any) { *h = append(*h, v.(pair)) }
// func (h *hp) Pop() (v any) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
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.