Skip to content

Tips & Common Mistakes

Expert advice to help you write correct, efficient graph code and avoid common pitfalls.


1. ALWAYS mark a node visited BEFORE enqueueing (in BFS), not after dequeuing
❌ Wrong: queue.push(neighbor) → mark visited when dequeued
✅ Right: mark visited + queue.push(neighbor) at same time
Why? Without early marking, the same node can be enqueued multiple times
→ infinite loops or TLE!
2. For grids, define directions array outside loops:
const dirs = [[0,1],[0,-1],[1,0],[-1,0]]; // Right, Left, Down, Up
3. Use modifying the grid itself as "visited" only if you can restore it,
or if the problem allows mutation.
4. In Dijkstra, always check if current distance > stored distance when popping:
if (currDist > distances.get(node)) continue; // Stale entry, skip!
5. For disconnected graphs, always loop through ALL nodes, not just from one start:
for (let i = 0; i < n; i++) {
if (!visited.has(i)) dfs(i); // Covers all components!
}

MistakeWhy It’s WrongFix
Not checking grid boundsArrayIndexOutOfBounds / wrong answersAlways check r >= 0 && r < rows && c >= 0 && c < cols
Forgetting to mark visitedInfinite loops in cyclic graphsMark visited immediately on discover
Using DFS for shortest pathDFS doesn’t guarantee shortest pathUse BFS for unweighted shortest path
Using Dijkstra with negative weightsGives wrong answersUse Bellman-Ford for negative weights
Off-by-one in topological sortMissing last node, wrong orderEnsure all V nodes are in result
Modifying graph while iteratingUndefined behaviorWork on a copy or use separate visited
Wrong base case in recursionStack overflow or wrong answerAlways have clear termination conditions

Search from both source and target simultaneously. Reduces complexity from O(b^d) to O(b^(d/2)).

Normal BFS: Bidirectional BFS:
Source → → → → Target Source → → | ← ← Target
Queue size grows Two smaller queues meet in middle
exponentially! 50%+ reduction in explored nodes

Use for: Word Ladder, shortest path problems with known source AND target.

function bidirectionalBFS(graph, start, end) {
if (start === end) return 0;
let queueStart = new Set([start]);
let queueEnd = new Set([end]);
const visitedStart = new Set([start]);
const visitedEnd = new Set([end]);
let distance = 1;
while (queueStart.size > 0 && queueEnd.size > 0) {
// Always expand the smaller queue
if (queueStart.size > queueEnd.size) {
[queueStart, queueEnd] = [queueEnd, queueStart];
[visitedStart, visitedEnd] = [visitedEnd, visitedStart];
}
const nextQueue = new Set();
for (const node of queueStart) {
for (const neighbor of graph[node] || []) {
if (visitedEnd.has(neighbor)) return distance;
if (!visitedStart.has(neighbor)) {
visitedStart.add(neighbor);
nextQueue.add(neighbor);
}
}
}
queueStart = nextQueue;
distance++;
}
return -1;
}

Return as soon as target is found. Don’t continue BFS after finding the destination!

  • Array: O(1) lookup, but needs integer node IDs
  • Set: O(1) average, works with any hashable node
  • For grids: Encode (r,c) as r * cols + c for O(1) array lookup

Build adjacency list as you read input — don’t rebuild later.

Use a proper min-heap for Dijkstra (not array.sort() inside the loop). In JS, implement with a binary heap or use a library.

Store parent pointers during BFS/Dijkstra to trace back the path.

parent[neighbor] = current; // Store how we reached each node
// Then trace: end → parent[end] → ... → start

Edge CaseWhy It Matters
Empty graph (no nodes/edges)BFS/DFS from one node won’t reach all!
Single node (self-loop?)Check if self-loops are allowed
Disconnected graphBFS/DFS from one node won’t reach all components
All nodes isolatedEach node is its own component
Negative weight cyclesBellman-Ford detects these
Dense vs sparse graphChoose representation wisely
Grid with all 0s or all 1sTest extreme grid configurations
Source == DestinationDistance = 0, return immediately
Multiple valid answersTopological sort, MST may have multiple valid solutions

┌─────────────────────────────────────────────────────────────────┐
│ GRAPH ALGORITHMS CHEAT SHEET │
├──────────────────────┬──────────────────────────────────────────┤
│ PROBLEM │ ALGORITHM │
├──────────────────────┼──────────────────────────────────────────┤
│ Shortest path │ BFS (unweighted) │
│ (unweighted) │ │
├──────────────────────┼──────────────────────────────────────────┤
│ Shortest path │ Dijkstra (non-negative weights) │
│ (weighted) │ Bellman-Ford (negative weights) │
├──────────────────────┼──────────────────────────────────────────┤
│ All-pairs shortest │ Floyd-Warshall │
├──────────────────────┼──────────────────────────────────────────┤
│ Cycle detection │ DFS (undirected: parent; directed: stack)│
├──────────────────────┼──────────────────────────────────────────┤
│ Topological order │ Kahn's BFS or DFS post-order │
├──────────────────────┼──────────────────────────────────────────┤
│ Components │ DFS/BFS loop or Union-Find │
├──────────────────────┼──────────────────────────────────────────┤
│ Minimum spanning │ Kruskal's (sparse) / Prim's (dense) │
│ tree │ │
├──────────────────────┼──────────────────────────────────────────┤
│ Bipartite check │ BFS/DFS 2-coloring │
├──────────────────────┼──────────────────────────────────────────┤
│ Multi-source spread │ Multi-source BFS │
├──────────────────────┼──────────────────────────────────────────┤
│ Dynamic connectivity │ Union-Find (DSU) │
└──────────────────────┴──────────────────────────────────────────┘

Explore Real-World Applications of graphs to deepen your understanding.