Graphs
IntermediateModel real-world networks — master BFS, DFS, topological sort, and shortest path algorithms.
Think of it this way
Think of a map of cities connected by roads. Some roads are two-way (undirected), some are one-way (directed). Some have tolls (weighted edges). Finding the fastest route between two cities is exactly what graph algorithms solve. Google Maps, Facebook friend suggestions, and Netflix recommendations all run on graph algorithms.
// Represent the graph as an adjacency list — city → list of neighbours
Map<String, List<String>> graph = new HashMap<>();
graph.put("Mumbai", List.of("Delhi", "Pune"));
graph.put("Delhi", List.of("Mumbai", "Jaipur"));
graph.put("Pune", List.of("Mumbai"));
// Mumbai — Delhi — Jaipur
// |
// PuneOverview
A graph is a collection of nodes (vertices) connected by edges. Graphs can be directed or undirected, weighted or unweighted, cyclic or acyclic. They model social networks, maps, dependency systems, and web links. In Java, graphs are typically represented as adjacency lists using Map<Integer, List<Integer>>. Knowing when to use BFS vs DFS vs Dijkstra is the core skill tested in interviews.
Time & Space Complexity
| Operation | Time | Space |
|---|---|---|
| BFS traversal | O(V + E) | O(V) |
| DFS traversal | O(V + E) | O(V) |
| Dijkstra's (shortest path) | O((V + E) log V) | O(V) |
| Topological sort | O(V + E) | O(V) |
| Cycle detection | O(V + E) | O(V) |
Java Implementation
import java.util.*;
public class GraphAlgorithms {
// DFS — iterative using stack, O(V + E)
public static void dfs(Map<Integer, List<Integer>> graph, int start) {
Set<Integer> visited = new HashSet<>();
Deque<Integer> stack = new ArrayDeque<>();
stack.push(start);
while (!stack.isEmpty()) {
int node = stack.pop();
if (visited.contains(node)) continue;
visited.add(node);
System.out.print(node + " ");
for (int neighbor : graph.getOrDefault(node, List.of())) {
if (!visited.contains(neighbor)) stack.push(neighbor);
}
}
}
// Topological sort using Kahn's algorithm (BFS) — O(V + E)
public static List<Integer> topologicalSort(int n, int[][] edges) {
int[] inDegree = new int[n];
Map<Integer, List<Integer>> adj = new HashMap<>();
for (int[] e : edges) {
adj.computeIfAbsent(e[0], k -> new ArrayList<>()).add(e[1]);
inDegree[e[1]]++;
}
Queue<Integer> queue = new ArrayDeque<>();
for (int i = 0; i < n; i++) if (inDegree[i] == 0) queue.offer(i);
List<Integer> order = new ArrayList<>();
while (!queue.isEmpty()) {
int node = queue.poll();
order.add(node);
for (int neighbor : adj.getOrDefault(node, List.of())) {
if (--inDegree[neighbor] == 0) queue.offer(neighbor);
}
}
return order.size() == n ? order : List.of(); // empty = cycle detected
}
// Number of islands — DFS on grid, O(m * n)
public static int numIslands(char[][] grid) {
int count = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == '1') { sink(grid, i, j); count++; }
}
}
return count;
}
private static void sink(char[][] grid, int i, int j) {
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] != '1') return;
grid[i][j] = '0';
sink(grid, i + 1, j); sink(grid, i - 1, j);
sink(grid, i, j + 1); sink(grid, i, j - 1);
}
}Key Points to Remember
- BFS finds shortest path in unweighted graphs; Dijkstra handles weighted graphs
// BFS — use a Queue; Dijkstra — use a PriorityQueue (min-heap on distance) Queue<Integer> bfs = new ArrayDeque<>(); PriorityQueue<int[]> dijkstra = new PriorityQueue<>(Comparator.comparingInt(a -> a[1])); - DFS is better for cycle detection, topological sort, and exploring all paths
void dfs(int node, boolean[] visited) { visited[node] = true; for (int nb : graph.get(node)) if (!visited[nb]) dfs(nb, visited); } - Union-Find (Disjoint Set Union) efficiently answers "are these two nodes connected?"
int find(int x) { return parent[x] == x ? x : (parent[x] = find(parent[x])); } void union(int a, int b) { parent[find(a)] = find(b); } - Topological sort only works on DAGs (Directed Acyclic Graphs) — cycles break it
- For grid problems, treat each cell as a node with 4 neighbours
int[][] dirs = {{1,0}, {-1,0}, {0,1}, {0,-1}}; // down, up, right, left for (int[] d : dirs) { int nr = row + d[0], nc = col + d[1]; if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) // in-bounds check queue.offer(new int[]{nr, nc}); }
Interview Questions
Sign in to ask AriaNumber of islands
Course schedule — detect cycle in directed graph
Shortest path in a binary matrix
Clone a graph
Word ladder — shortest transformation sequence
Ask Aria about Graphs
Your personal AI tutor — ask anything about this concept