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.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
There is a bi-directional graph with n vertices, where each vertex is labeled from 0 to n - 1. The edges in the graph are represented by a given 2D integer array edges, where edges[i] = [ui, vi] denotes an edge between vertex ui and vertex vi. Every vertex pair is connected by at most one edge, and no vertex has an edge to itself.
Return the length of the shortest cycle in the graph. If no cycle exists, return -1.
A cycle is a path that starts and ends at the same node, and each edge in the path is used only once.
Example 1:
Input: n = 7, edges = [[0,1],[1,2],[2,0],[3,4],[4,5],[5,6],[6,3]] Output: 3 Explanation: The cycle with the smallest length is : 0 -> 1 -> 2 -> 0
Example 2:
Input: n = 4, edges = [[0,1],[0,2]] Output: -1 Explanation: There are no cycles in this graph.
Constraints:
2 <= n <= 10001 <= edges.length <= 1000edges[i].length == 20 <= ui, vi < nui != viProblem summary: There is a bi-directional graph with n vertices, where each vertex is labeled from 0 to n - 1. The edges in the graph are represented by a given 2D integer array edges, where edges[i] = [ui, vi] denotes an edge between vertex ui and vertex vi. Every vertex pair is connected by at most one edge, and no vertex has an edge to itself. Return the length of the shortest cycle in the graph. If no cycle exists, return -1. A cycle is a path that starts and ends at the same node, and each edge in the path is used only once.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: General problem-solving
7 [[0,1],[1,2],[2,0],[3,4],[4,5],[5,6],[6,3]]
4 [[0,1],[0,2]]
redundant-connection)longest-cycle-in-a-graph)divide-nodes-into-the-maximum-number-of-groups)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2608: Shortest Cycle in a Graph
class Solution {
private List<Integer>[] g;
private final int inf = 1 << 30;
public int findShortestCycle(int n, int[][] edges) {
g = new List[n];
Arrays.setAll(g, k -> new ArrayList<>());
for (var e : edges) {
int u = e[0], v = e[1];
g[u].add(v);
g[v].add(u);
}
int ans = inf;
for (var e : edges) {
int u = e[0], v = e[1];
ans = Math.min(ans, bfs(u, v));
}
return ans < inf ? ans : -1;
}
private int bfs(int u, int v) {
int[] dist = new int[g.length];
Arrays.fill(dist, inf);
dist[u] = 0;
Deque<Integer> q = new ArrayDeque<>();
q.offer(u);
while (!q.isEmpty()) {
int i = q.poll();
for (int j : g[i]) {
if ((i == u && j == v) || (i == v && j == u) || dist[j] != inf) {
continue;
}
dist[j] = dist[i] + 1;
q.offer(j);
}
}
return dist[v] + 1;
}
}
// Accepted solution for LeetCode #2608: Shortest Cycle in a Graph
func findShortestCycle(n int, edges [][]int) int {
g := make([][]int, n)
for _, e := range edges {
u, v := e[0], e[1]
g[u] = append(g[u], v)
g[v] = append(g[v], u)
}
const inf = 1 << 30
bfs := func(u, v int) int {
dist := make([]int, n)
for i := range dist {
dist[i] = inf
}
dist[u] = 0
q := []int{u}
for len(q) > 0 {
i := q[0]
q = q[1:]
for _, j := range g[i] {
if (i == u && j == v) || (i == v && j == u) || dist[j] != inf {
continue
}
dist[j] = dist[i] + 1
q = append(q, j)
}
}
return dist[v] + 1
}
ans := inf
for _, e := range edges {
u, v := e[0], e[1]
ans = min(ans, bfs(u, v))
}
if ans < inf {
return ans
}
return -1
}
# Accepted solution for LeetCode #2608: Shortest Cycle in a Graph
class Solution:
def findShortestCycle(self, n: int, edges: List[List[int]]) -> int:
def bfs(u: int, v: int) -> int:
dist = [inf] * n
dist[u] = 0
q = deque([u])
while q:
i = q.popleft()
for j in g[i]:
if (i, j) != (u, v) and (j, i) != (u, v) and dist[j] == inf:
dist[j] = dist[i] + 1
q.append(j)
return dist[v] + 1
g = defaultdict(set)
for u, v in edges:
g[u].add(v)
g[v].add(u)
ans = min(bfs(u, v) for u, v in edges)
return ans if ans < inf else -1
// Accepted solution for LeetCode #2608: Shortest Cycle in a Graph
// Rust example auto-generated from java 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 (java):
// // Accepted solution for LeetCode #2608: Shortest Cycle in a Graph
// class Solution {
// private List<Integer>[] g;
// private final int inf = 1 << 30;
//
// public int findShortestCycle(int n, int[][] edges) {
// g = new List[n];
// Arrays.setAll(g, k -> new ArrayList<>());
// for (var e : edges) {
// int u = e[0], v = e[1];
// g[u].add(v);
// g[v].add(u);
// }
// int ans = inf;
// for (var e : edges) {
// int u = e[0], v = e[1];
// ans = Math.min(ans, bfs(u, v));
// }
// return ans < inf ? ans : -1;
// }
//
// private int bfs(int u, int v) {
// int[] dist = new int[g.length];
// Arrays.fill(dist, inf);
// dist[u] = 0;
// Deque<Integer> q = new ArrayDeque<>();
// q.offer(u);
// while (!q.isEmpty()) {
// int i = q.poll();
// for (int j : g[i]) {
// if ((i == u && j == v) || (i == v && j == u) || dist[j] != inf) {
// continue;
// }
// dist[j] = dist[i] + 1;
// q.offer(j);
// }
// }
// return dist[v] + 1;
// }
// }
// Accepted solution for LeetCode #2608: Shortest Cycle in a Graph
function findShortestCycle(n: number, edges: number[][]): number {
const g: number[][] = new Array(n).fill(0).map(() => []);
for (const [u, v] of edges) {
g[u].push(v);
g[v].push(u);
}
const inf = 1 << 30;
let ans = inf;
const bfs = (u: number, v: number) => {
const dist: number[] = new Array(n).fill(inf);
dist[u] = 0;
const q: number[] = [u];
while (q.length) {
const i = q.shift()!;
for (const j of g[i]) {
if ((i == u && j == v) || (i == v && j == u) || dist[j] != inf) {
continue;
}
dist[j] = dist[i] + 1;
q.push(j);
}
}
return 1 + dist[v];
};
for (const [u, v] of edges) {
ans = Math.min(ans, bfs(u, v));
}
return ans < inf ? ans : -1;
}
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.