Interview Setbook · Part 4 of 6 · Q106–Q140
C++ Mastery Series · Interview Prep

The Interview
Problem Setbook

Part 4 of 6. Graphs — the most expansive topic in interviews. BFS/DFS on grids and adjacency lists, topological sort, Dijkstra, Bellman-Ford, Union-Find, and the hardest graph problems that separate Codeforces Pupil from Expert.

Part 4 · Q106–Q140 BFS & DFS on Graphs Topological Sort Shortest Paths Union-Find / DSU Advanced Graph
Chapter 10 · Q106–Q118 · Graph BFS & DFS
Graph BFS & DFS — Traversals, Connectivity & Grid Problems
BFS vs DFS — When to Use Which

BFS (Queue, level-by-level): Use when you need the SHORTEST PATH in an unweighted graph, minimum number of steps/moves, or level-order processing. BFS guarantees the first time you reach a node is via the shortest path.
DFS (Stack/Recursion, depth-first): Use when you need to explore all paths, detect cycles, find connected components, or check reachability. DFS explores one branch fully before backtracking.
Grid = Graph: Every grid problem where you move between cells is a graph. Cells are nodes, valid moves are edges. The 4-directional movement array dx[]={0,0,1,-1}, dy[]={1,-1,0,0} is your adjacency list.

Q106 · MEDIUM Number of Islands
GraphDFSGrid
LeetCode #200
Must KnowAsked 8,000+Grid DFS Template

Count the number of islands in a 2D binary grid ('1'=land, '0'=water). An island is a group of '1's connected 4-directionally.

Input[["1","1","0","0","0"], ["1","1","0","0","0"], ["0","0","1","0","0"], ["0","0","0","1","1"]]
Output3
Decode — Flood Fill: Each DFS Burns One Complete Island

Scan the grid. When you find an unvisited '1': increment count, then DFS from that cell to mark all connected land as visited (change to '0'). Each DFS call explores one complete island. Count = number of DFS calls made.

Grid (simplified 3×3): [[1,1,0],[1,0,0],[0,0,1]] Scan (0,0)='1' → count=1, DFS floods: (0,0)→'0', visit (0,1)→'0', visit (1,0)→'0' All connected land marked '0' Scan (0,1)='0' skip, (0,2)='0' skip Scan (1,0)='0' skip, (1,1)='0' skip, (1,2)='0' skip Scan (2,0)='0' skip, (2,1)='0' skip Scan (2,2)='1' → count=2, DFS floods (2,2)→'0' Answer: 2
C++ — DFS Flood Fill O(R×C) int numIslands(vector<vector<char>>& grid) { int R=grid.size(), C=grid[0].size(), count=0; int dx[]={0,0,1,-1}, dy[]={1,-1,0,0}; function<void(int,int)> dfs=[&](int r, int c){ if(r<0||r>=R||c<0||c>=C||grid[r][c]!='1') return; grid[r][c]='0'; // Mark visited for(int d=0;d<4;d++) dfs(r+dx[d],c+dy[d]); // Visit all 4 neighbours }; for(int i=0;i<R;i++) for(int j=0;j<C;j++) if(grid[i][j]=='1'){ dfs(i,j); count++; } return count; }
TimeO(R×C)
SpaceO(R×C) stack
VariantsMax Area of Island · Surrounded Regions · Pacific Atlantic
Q107 · MEDIUM Max Area of Island
GraphDFSGrid
LeetCode #695
Must KnowDFS Returns Area Count

Return the maximum area (number of cells) of an island. Return 0 if no island.

Decode — DFS Returns Island Size; Track Maximum

Same flood fill as Q106, but DFS now returns the count of cells in the island instead of just marking. Each recursive call returns 1 (current cell) + sum of sizes from valid neighbours.

C++ Solution — O(R×C) int maxAreaOfIsland(vector<vector<int>>& grid) { int R=grid.size(), C=grid[0].size(), best=0; int dx[]={0,0,1,-1}, dy[]={1,-1,0,0}; function<int(int,int)> dfs=[&](int r,int c)->int{ if(r<0||r>=R||c<0||c>=C||grid[r][c]!=1) return 0; grid[r][c]=0; int area=1; for(int d=0;d<4;d++) area+=dfs(r+dx[d],c+dy[d]); return area; }; for(int i=0;i<R;i++) for(int j=0;j<C;j++) if(grid[i][j]==1) best=max(best, dfs(i,j)); return best; }
TimeO(R×C)
SpaceO(R×C)
Q108 · MEDIUM Rotting Oranges (Multi-Source BFS)
GraphMulti-BFSGrid
LeetCode #994
Must KnowMulti-Source BFS Template

Grid: 0=empty, 1=fresh orange, 2=rotten. Each minute, rotten oranges rot adjacent (4-dir) fresh ones. Return minimum minutes until no fresh oranges, or -1 if impossible.

Input[[2,1,1],[1,1,0],[0,1,1]]
Output4
Decode — All Rotten Oranges Start Simultaneously (Multi-Source BFS)

Key insight: ALL rotten oranges start spreading at minute 0 simultaneously. Push them ALL into the BFS queue before starting. Then process level by level — each level = 1 minute. Count fresh oranges; after BFS, if any remain → return -1.

[[2,1,1],[1,1,0],[0,1,1]] Init: queue=[(0,0)], fresh=6 Minute 1: process (0,0). Rot (0,1) and (1,0). fresh=4 queue=[(0,1),(1,0)] Minute 2: process (0,1). Rot (0,2). process (1,0). Rot (1,1). fresh=2 queue=[(0,2),(1,1)] Minute 3: process (0,2) no new. process (1,1). Rot (2,1). fresh=1 queue=[(2,1)] Minute 4: process (2,1). Rot (2,2). fresh=0 queue=[(2,2)] fresh=0 → return 4
C++ Solution — O(R×C) int orangesRotting(vector<vector<int>>& grid) { int R=grid.size(), C=grid[0].size(), fresh=0, minutes=0; queue<pair<int,int>> q; int dx[]={0,0,1,-1}, dy[]={1,-1,0,0}; for(int i=0;i<R;i++) for(int j=0;j<C;j++){ if(grid[i][j]==2) q.push({i,j}); // All rotten oranges start together if(grid[i][j]==1) fresh++; } while(!q.empty() && fresh>0){ minutes++; for(int sz=q.size();sz>0;sz--){ auto[r,c]=q.front(); q.pop(); for(int d=0;d<4;d++){ int nr=r+dx[d], nc=c+dy[d]; if(nr>=0&&nr<R&&nc>=0&&nc<C&&grid[nr][nc]==1){ grid[nr][nc]=2; fresh--; q.push({nr,nc}); } } } } return fresh==0 ? minutes : -1; }
TimeO(R×C)
SpaceO(R×C)
PatternMulti-source BFS · Walls and Gates · 0-1 Matrix
Q109 · MEDIUM 01 Matrix — Nearest 0 Distance
GraphMulti-BFSGrid
LeetCode #542
Must KnowMulti-Source BFS from All 0s Simultaneously

Given a binary matrix, return a matrix of the same size where each cell contains the distance to the nearest 0.

Input[[0,0,0],[0,1,0],[1,1,1]]
Output[[0,0,0],[0,1,0],[1,2,1]]
Decode — BFS from All 0s Simultaneously; Distance Radiates Outward

Don't BFS from each 1 to find its nearest 0 (that would be O(n²)). Instead, start BFS from ALL 0 cells simultaneously. Distance = BFS level when you first reach a cell. This is the same multi-source BFS pattern as Q108.

C++ Solution — O(R×C) vector<vector<int>> updateMatrix(vector<vector<int>>& mat) { int R=mat.size(), C=mat[0].size(); vector<vector<int>> dist(R, vector<int>(C, INT_MAX)); queue<pair<int,int>> q; int dx[]={0,0,1,-1}, dy[]={1,-1,0,0}; // Seed: all 0 cells have distance 0 for(int i=0;i<R;i++) for(int j=0;j<C;j++) if(mat[i][j]==0){ dist[i][j]=0; q.push({i,j}); } // BFS radiates distance outward while(!q.empty()){ auto[r,c]=q.front(); q.pop(); for(int d=0;d<4;d++){ int nr=r+dx[d], nc=c+dy[d]; if(nr>=0&&nr<R&&nc>=0&&nc<C && dist[nr][nc]==INT_MAX){ dist[nr][nc]=dist[r][c]+1; q.push({nr,nc}); } } } return dist; }
TimeO(R×C)
SpaceO(R×C)
Q110 · MEDIUM Walls and Gates
GraphMulti-BFSGrid
LeetCode #286 (Premium) / GFG
Must KnowSame Multi-Source BFS Pattern

Fill each empty room (INF) with distance to its nearest gate (0). Walls are -1. Multi-source BFS from all gates simultaneously.

C++ — same as Q109 with gate=0, wall=-1, room=INF void wallsAndGates(vector<vector<int>>& rooms){ int R=rooms.size(), C=rooms[0].size(), INF=2147483647; queue<pair<int,int>> q; int dx[]={0,0,1,-1}, dy[]={1,-1,0,0}; // Seed all gates for(int i=0;i<R;i++) for(int j=0;j<C;j++) if(rooms[i][j]==0) q.push({i,j}); while(!q.empty()){ auto[r,c]=q.front();q.pop(); for(int d=0;d<4;d++){ int nr=r+dx[d],nc=c+dy[d]; if(nr>=0&&nr<R&&nc>=0&&nc<C&&rooms[nr][nc]==INF){ rooms[nr][nc]=rooms[r][c]+1; q.push({nr,nc}); } } } }
TimeO(R×C)
SpaceO(R×C)
Q111 · MEDIUM Pacific Atlantic Water Flow
GraphDFSGrid
LeetCode #417
Must KnowReverse Flow — BFS from Oceans Inward

Find all cells from which water can flow to BOTH the Pacific (top/left edges) and Atlantic (bottom/right edges). Water flows to equal or lower neighbours.

Decode — Reverse the Direction: BFS Uphill from Each Ocean's Border

Instead of simulating water flow downward from each cell (O(n²m²)), reverse: BFS/DFS uphill from each ocean's border cells. A cell can "reach the ocean" if the next cell is equal or higher. Do this separately for Pacific and Atlantic. Cells in both sets are the answer.

C++ Solution — O(R×C) vector<vector<int>> pacificAtlantic(vector<vector<int>>& h) { int R=h.size(), C=h[0].size(); int dx[]={0,0,1,-1}, dy[]={1,-1,0,0}; vector<vector<bool>> pac(R,vector<bool>(C,false)); vector<vector<bool>> atl(R,vector<bool>(C,false)); auto bfs=[&](queue<pair<int,int>>& q, vector<vector<bool>>& vis){ while(!q.empty()){ auto[r,c]=q.front();q.pop(); for(int d=0;d<4;d++){ int nr=r+dx[d],nc=c+dy[d]; if(nr>=0&&nr<R&&nc>=0&&nc<C&&!vis[nr][nc]&&h[nr][nc]>=h[r][c]){ vis[nr][nc]=true; q.push({nr,nc}); } } } }; queue<pair<int,int>> pq, aq; for(int i=0;i<R;i++){ pac[i][0]=atl[i][C-1]=true; pq.push({i,0}); aq.push({i,C-1}); } for(int j=0;j<C;j++){ pac[0][j]=atl[R-1][j]=true; pq.push({0,j}); aq.push({R-1,j}); } bfs(pq,pac); bfs(aq,atl); vector<vector<int>> res; for(int i=0;i<R;i++) for(int j=0;j<C;j++) if(pac[i][j]&&atl[i][j]) res.push_back({i,j}); return res; }
TimeO(R×C)
SpaceO(R×C)
Q112 · MEDIUM Surrounded Regions
GraphDFSGrid
LeetCode #130
Mark Border-Connected 'O's First, Then Flip

Flip all 'O' regions not connected to the border to 'X'. Border-connected 'O' regions remain.

Input[["X","X","X","X"], ["X","O","O","X"], ["X","X","O","X"], ["X","O","X","X"]]
Output[["X","X","X","X"], ["X","X","X","X"], ["X","X","X","X"], ["X","O","X","X"]]
Decode — Solve the Complement: Mark What Should NOT Be Flipped

Instead of finding enclosed regions (hard), find border-connected 'O' regions (easy: DFS from each border 'O'). Mark them safe (e.g., 'S'). Then flip all remaining 'O' to 'X' and restore 'S' to 'O'.

C++ Solution — O(R×C) void solve(vector<vector<char>>& b) { int R=b.size(), C=b[0].size(); int dx[]={0,0,1,-1}, dy[]={1,-1,0,0}; function<void(int,int)> safe=[&](int r,int c){ if(r<0||r>=R||c<0||c>=C||b[r][c]!='O') return; b[r][c]='S'; // Mark as safe for(int d=0;d<4;d++) safe(r+dx[d],c+dy[d]); }; // Mark all border-connected O's as safe for(int i=0;i<R;i++) safe(i,0), safe(i,C-1); for(int j=0;j<C;j++) safe(0,j), safe(R-1,j); // Flip: O→X (enclosed), S→O (safe/border) for(int i=0;i<R;i++) for(int j=0;j<C;j++) b[i][j] = b[i][j]=='S' ? 'O' : (b[i][j]=='O' ? 'X' : b[i][j]); }
TimeO(R×C)
SpaceO(R×C)
Q113 · HARD Word Ladder (BFS State Space)
GraphBFSString
LeetCode #127
Must KnowFAANG FavouriteStrings as Graph Nodes

Given beginWord, endWord, and a wordList, find the shortest transformation sequence from begin to end where each step changes exactly one letter and each intermediate word must be in wordList. Return the number of words in the shortest sequence (0 if impossible).

Inputbegin="hit", end="cog" list=["hot","dot","dog","lot","log","cog"]
Output5
Pathhit→hot→dot→dog→cog
Decode — Words are Nodes; Edge Exists if They Differ by One Letter

This is BFS on an implicit graph. Each word is a node. Two words are connected if they differ by exactly one character. BFS finds the shortest path from beginWord to endWord. For each word in the queue, try changing each character to 'a'-'z' and check if the result is in the word set.

begin="hit" end="cog" Level 1: {hit} Try all 1-char changes of "hit": "ait","bit",...,"hot" ← in wordList! add to queue Level 2: {hot} 1-char changes: "dot","lot" ← both in list Level 3: {dot,lot} dot→"dog","log"; lot→"log" Level 4: {dog,log} dog→"cog" ← endWord! return level+1=5
C++ Solution — O(N×M²) where N=words, M=word length int ladderLength(string begin, string end, vector<string>& wordList) { unordered_set<string> wordSet(wordList.begin(), wordList.end()); if(!wordSet.count(end)) return 0; queue<string> q; q.push(begin); int level=1; while(!q.empty()){ for(int sz=q.size();sz>0;sz--){ string word=q.front();q.pop(); for(int i=0;i<(int)word.size();i++){ char orig=word[i]; for(char c='a';c<='z';c++){ if(c==orig) continue; word[i]=c; if(word==end) return level+1; if(wordSet.count(word)){ q.push(word); wordSet.erase(word); // Mark visited } word[i]=orig; } } } level++; } return 0; }
TimeO(N×M²)
SpaceO(N×M)
ExtensionBidirectional BFS halves the time in practice
Q114 · MEDIUM Clone Graph
GraphDFSHash
LeetCode #133
Must KnowMap Old Nodes to New Nodes

Deep copy (clone) an undirected graph. Each node has a value and a list of neighbours.

Decode — Hash Map of Old→New, DFS to Wire Neighbours

Use a hash map: visited[old_node] = new_node. DFS: if current node is already in map, return its clone (handles cycles). Otherwise: create clone, add to map, recursively clone all neighbours and add them to the clone's neighbour list.

C++ Solution — O(V+E) unordered_map<Node*,Node*> visited; Node* cloneGraph(Node* node){ if(!node) return nullptr; if(visited.count(node)) return visited[node]; // Already cloned Node* clone = new Node(node->val); visited[node] = clone; // Register BEFORE recursing (handles cycles) for(Node* nb : node->neighbors) clone->neighbors.push_back(cloneGraph(nb)); return clone; }
TimeO(V+E)
SpaceO(V)
Q115 · MEDIUM Number of Connected Components
GraphDFSUnion-Find
LeetCode #323 (Premium)
Must KnowDFS or Union-Find Both Work

Given n nodes (0 to n-1) and edges list, find the number of connected components.

C++ — DFS approach O(V+E) int countComponents(int n, vector<vector<int>>& edges){ vector<vector<int>> adj(n); for(auto& e:edges){ adj[e[0]].push_back(e[1]); adj[e[1]].push_back(e[0]); } vector<bool> vis(n,false); int count=0; function<void(int)> dfs=[&](int u){ vis[u]=true; for(int v:adj[u]) if(!vis[v]) dfs(v); }; for(int i=0;i<n;i++) if(!vis[i]){ dfs(i); count++; } return count; }
TimeO(V+E)
SpaceO(V+E)
Q116 · MEDIUM Is Graph Bipartite?
GraphBFSDFS
LeetCode #785
Must Know2-Coloring — BFS/DFS Assigns Colors

A graph is bipartite if nodes can be split into two sets where every edge connects a node from set A to set B (no edges within a set). Check if the given graph is bipartite.

Decode — 2-Coloring: Try to Color Graph With 2 Colors, No Conflicts

BFS/DFS with two colors (0 and 1). Color each node; assign the opposite color to all neighbours. If a neighbour already has the same color as the current node → conflict → not bipartite. Equivalent to: does the graph contain an odd-length cycle?

C++ Solution — O(V+E) bool isBipartite(vector<vector<int>>& graph){ int n=graph.size(); vector<int> color(n,-1); for(int start=0;start<n;start++){ if(color[start]!=-1) continue; queue<int> q; q.push(start); color[start]=0; while(!q.empty()){ int u=q.front();q.pop(); for(int v:graph[u]){ if(color[v]==-1){ color[v]=1-color[u]; q.push(v); } else if(color[v]==color[u]) return false; // Conflict! } } } return true; }
TimeO(V+E)
SpaceO(V)
Q117 · HARD Minimum Steps in Infinite Grid (Chebyshev Distance)
GraphMath
Codeforces 263A
Chess King Distance = max(|dx|,|dy|)

A chess king moves to any of 8 adjacent cells per step. Given a sequence of points to visit in order, find the minimum total steps.

Decode — King Distance Between Two Points = max(|Δx|, |Δy|)

A king can move diagonally so it covers both horizontal and vertical distance simultaneously. To move from (x1,y1) to (x2,y2): the king needs max(|x2-x1|, |y2-y1|) steps — diagonal moves cover both coordinates at once.

C++ Solution — O(n) long long minSteps(vector<pair<int,int>>& pts){ long long total=0; for(int i=1;i<(int)pts.size();i++){ int dx=abs(pts[i].first -pts[i-1].first); int dy=abs(pts[i].second-pts[i-1].second); total += max(dx,dy); // Chebyshev distance } return total; }
TimeO(n)
SpaceO(1)
Q118 · HARD Shortest Path in Binary Matrix
GraphBFSGrid
LeetCode #1091
Must KnowBFS on 8-Directional Grid

Find the shortest clear path (all 0s) from top-left to bottom-right of a binary matrix. Movement is 8-directional. Return path length or -1.

C++ Solution — O(N²) BFS int shortestPathBinaryMatrix(vector<vector<int>>& grid){ int n=grid.size(); if(grid[0][0]||grid[n-1][n-1]) return -1; queue<tuple<int,int,int>> q; // {r,c,dist} q.push({0,0,1}); grid[0][0]=1; // Mark visited int dirs[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}}; while(!q.empty()){ auto[r,c,d]=q.front();q.pop(); if(r==n-1&&c==n-1) return d; for(auto& dir:dirs){ int nr=r+dir[0],nc=c+dir[1]; if(nr>=0&&nr<n&&nc>=0&&nc<n&&!grid[nr][nc]){ grid[nr][nc]=1; q.push({nr,nc,d+1}); } } } return -1; }
TimeO(N²)
SpaceO(N²)
↑ back to top
Chapter 11 · Q119–Q125 · Topological Sort
Topological Sort — Dependencies, Ordering & Cycle Detection in DAGs
Topological Sort — Two Algorithms, One Purpose

Kahn's Algorithm (BFS): Compute in-degrees. Push all nodes with in-degree 0 into a queue. Process: pop node, add to order, decrement neighbours' in-degrees. If a neighbour reaches 0, push it. If final order size < n → cycle exists.
DFS-based: Run DFS. After exploring all neighbours of a node, push it onto a stack. Reverse the stack = topological order. Use 3-state coloring (white/grey/black) for cycle detection.
When to use: Task scheduling, build systems, course prerequisites, dependency resolution — anything with "A must come before B" constraints.

Q119 · MEDIUM Course Schedule I — Detect Cycle
GraphTopo Sort
LeetCode #207
Must KnowAsked 5,000+Kahn's Algorithm Template

n courses, prereqs[i]=[a,b] means take b before a. Can you finish all courses? (= Does the prerequisite graph have a cycle?)

Inputn=2, prereqs=[[1,0]]
Outputtrue
Input 2n=2, prereqs=[[1,0],[0,1]]
Output 2false (cycle)
Decode — Can Finish All = Graph Has No Cycle

Build a directed graph where edge b→a means "b is prerequisite of a". Apply Kahn's algorithm. If all n nodes are processed (added to topological order), no cycle exists and all courses can be finished.

n=4, prereqs=[[1,0],[2,0],[3,1],[3,2]] Graph: 0→1, 0→2, 1→3, 2→3 in-degree: [0, 1, 1, 2] Queue (in-degree=0): [0] Process 0: done=1, decrement 1,2 → in-degree=[0,0,0,2] Queue: [1,2] Process 1: done=2, decrement 3 → in-degree=[0,0,0,1] Process 2: done=3, decrement 3 → in-degree=[0,0,0,0] Queue: [3] Process 3: done=4 done==n → No cycle → true ✓
C++ — Kahn's Algorithm O(V+E) bool canFinish(int n, vector<vector<int>>& prereqs) { vector<vector<int>> adj(n); vector<int> indeg(n,0); for(auto& p:prereqs){ adj[p[1]].push_back(p[0]); indeg[p[0]]++; } queue<int> q; for(int i=0;i<n;i++) if(indeg[i]==0) q.push(i); int done=0; while(!q.empty()){ int u=q.front();q.pop(); done++; for(int v:adj[u]) if(--indeg[v]==0) q.push(v); } return done==n; }
TimeO(V+E)
SpaceO(V+E)
Q120 · MEDIUM Course Schedule II — Return Order
GraphTopo Sort
LeetCode #210
Must KnowKahn's — Return the Order Vector

Return the order in which to take courses such that all prerequisites are satisfied. Return empty array if impossible (cycle).

C++ — Kahn's Modified to Record Order vector<int> findOrder(int n, vector<vector<int>>& prereqs){ vector<vector<int>> adj(n); vector<int> indeg(n,0); for(auto& p:prereqs){ adj[p[1]].push_back(p[0]); indeg[p[0]]++; } queue<int> q; for(int i=0;i<n;i++) if(indeg[i]==0) q.push(i); vector<int> order; while(!q.empty()){ int u=q.front();q.pop(); order.push_back(u); // Record in topological order for(int v:adj[u]) if(--indeg[v]==0) q.push(v); } return (int)order.size()==n ? order : vector<int>{}; }
TimeO(V+E)
SpaceO(V+E)
Q121 · HARD Alien Dictionary
GraphTopo Sort
LeetCode #269 (Premium) / LintCode
Must KnowFAANG FavouriteDerive Order from Adjacent Words

Given a sorted alien language dictionary (sorted by alien alphabet), derive the character ordering. Return one valid ordering of characters, or "" if invalid.

Input["wrt","wrf","er","ett","rftt"]
Output"wertf"
Decode — Compare Adjacent Words to Extract Character Order Constraints

Compare each pair of adjacent words. Find the first position where they differ — that character must come before the other in the alien alphabet. Build a directed graph from these constraints. Apply topological sort. Watch for: word2 is prefix of word1 (invalid), cycles (invalid).

["wrt","wrf","er","ett","rftt"] Compare "wrt" vs "wrf": first diff at pos 2: 't' before 'f' → t→f Compare "wrf" vs "er": first diff at pos 0: 'w' before 'e' → w→e Compare "er" vs "ett": first diff at pos 1: 'r' before 't' → r→t Compare "ett" vs "rftt":first diff at pos 0: 'e' before 'r' → e→r Edges: t→f, w→e, r→t, e→r Topo sort: w→e→r→t→f → "wertf"
C++ Solution — O(C) where C=total chars in all words string alienOrder(vector<string>& words){ map<char,set<char>> adj; map<char,int> indeg; for(auto& w:words) for(char c:w) indeg[c]=0; for(int i=0;i<(int)words.size()-1;i++){ string& w1=words[i], &w2=words[i+1]; int len=min(w1.size(),w2.size()); bool found=false; for(int j=0;j<len;j++){ if(w1[j]!=w2[j]){ if(!adj[w1[j]].count(w2[j])){ adj[w1[j]].insert(w2[j]); indeg[w2[j]]++; } found=true; break; } } if(!found&&w1.size()>w2.size()) return ""; // w1 is prefix of w2 — invalid } queue<char> q; for(auto&[c,d]:indeg) if(d==0) q.push(c); string res; while(!q.empty()){ char c=q.front();q.pop(); res+=c; for(char nb:adj[c]) if(--indeg[nb]==0) q.push(nb); } return res.size()==indeg.size() ? res : ""; }
TimeO(C)
SpaceO(1) — 26 chars max
Q122 · MEDIUM Sequence Reconstruction — Unique Shortest Supersequence
GraphTopo Sort
LeetCode #444 (Premium)
Topo Sort with Queue Never Has >1 Choice

Check if org is the only shortest supersequence that can be reconstructed from sequences. I.e., the topological order is unique and matches org.

Decode — Unique Topo Order = Queue Never Has More Than 1 Element

Apply Kahn's algorithm. At each step, if the queue has more than 1 element, multiple valid orderings exist → org cannot be the unique reconstruction. Also verify each step matches org.

C++ Solution bool sequenceReconstruction(vector<int>& org, vector<vector<int>>& seqs){ int n=org.size(); vector<set<int>> adj(n+1); vector<int> indeg(n+1,0); for(auto& s:seqs) for(int i=1;i<(int)s.size();i++) if(!adj[s[i-1]].count(s[i])){ adj[s[i-1]].insert(s[i]); indeg[s[i]]++; } queue<int> q; for(int i=1;i<=n;i++) if(indeg[i]==0) q.push(i); int idx=0; while(!q.empty()){ if(q.size()>1) return false; // Multiple choices → not unique int u=q.front();q.pop(); if(org[idx++]!=u) return false; for(int v:adj[u]) if(--indeg[v]==0) q.push(v); } return idx==n; }
TimeO(V+E)
SpaceO(V+E)
Q123 · MEDIUM Find Eventual Safe States
GraphDFSTopo Sort
LeetCode #802
Safe = Not on Any Cycle. Reverse Graph + Topo Sort.

A node is "safe" if every path from it eventually leads to a terminal node (no cycles reachable). Return all safe nodes sorted.

Decode — Reverse the Graph, Apply Kahn's from Terminal Nodes

In the reversed graph, terminal nodes (sinks → no outgoing) become sources. Safe nodes in original = nodes reachable from terminals in reversed graph = apply Kahn's starting from nodes with outdegree 0 in original (= indegree 0 in reversed).

C++ Solution — Reverse Graph + Kahn's vector<int> eventualSafeNodes(vector<vector<int>>& graph){ int n=graph.size(); vector<vector<int>> rev(n); vector<int> outdeg(n,0); for(int u=0;u<n;u++) for(int v:graph[u]){ rev[v].push_back(u); outdeg[u]++; } queue<int> q; for(int i=0;i<n;i++) if(outdeg[i]==0) q.push(i); vector<bool> safe(n,false); while(!q.empty()){ int u=q.front();q.pop(); safe[u]=true; for(int v:rev[u]) if(--outdeg[v]==0) q.push(v); } vector<int> res; for(int i=0;i<n;i++) if(safe[i]) res.push_back(i); return res; }
TimeO(V+E)
SpaceO(V+E)
Q124 · HARD Minimum Height Trees
GraphTopo-like
LeetCode #310
Must KnowLeaf Pruning — Remove Leaves Layer by Layer

Find all roots of minimum height trees in an undirected tree with n nodes. Return all such root labels.

Decode — The Optimal Roots Are in the Centre. Prune Leaves to Find Them.

The center of a tree minimizes its height (at most 2 central nodes). Use a topological-sort-like approach: repeatedly remove leaf nodes (degree 1) layer by layer. The last 1 or 2 remaining nodes are the centers and the answer.

C++ Solution — O(n) vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges){ if(n==1) return {0}; vector<set<int>> adj(n); for(auto& e:edges){ adj[e[0]].insert(e[1]); adj[e[1]].insert(e[0]); } queue<int> leaves; for(int i=0;i<n;i++) if(adj[i].size()==1) leaves.push(i); int remaining=n; while(remaining>2){ int sz=leaves.size(); remaining-=sz; while(sz--){ int u=leaves.front();leaves.pop(); int nb=*adj[u].begin(); adj[nb].erase(u); if(adj[nb].size()==1) leaves.push(nb); } } vector<int> res; while(!leaves.empty()){ res.push_back(leaves.front());leaves.pop(); } return res; }
TimeO(n)
SpaceO(n)
Q125 · HARD Parallel Courses III (Critical Path)
GraphTopo SortDP
LeetCode #2050
Topo DP: dp[v] = max(dp[u] for u in prereqs) + time[v]

n courses with durations and prerequisites. Courses can be taken in parallel. Find the minimum time to finish all courses (= longest path in DAG = critical path).

Decode — Critical Path = Longest Path in DAG via Topo DP

Process nodes in topological order. dp[v] = earliest finish time for course v = time[v] + max(dp[u]) for all prerequisites u. The answer is max(dp[i]) over all nodes.

C++ Solution — O(V+E) int minimumTime(int n, vector<vector<int>>& rels, vector<int>& time){ vector<vector<int>> adj(n+1); vector<int> indeg(n+1,0); for(auto& r:rels){ adj[r[0]].push_back(r[1]); indeg[r[1]]++; } vector<int> dp(n+1,0); queue<int> q; for(int i=1;i<=n;i++) if(indeg[i]==0){ q.push(i); dp[i]=time[i-1]; } while(!q.empty()){ int u=q.front();q.pop(); for(int v:adj[u]){ dp[v]=max(dp[v], dp[u]+time[v-1]); // Earliest finish = max prerequisite + own time if(--indeg[v]==0) q.push(v); } } return *max_element(dp.begin(),dp.end()); }
TimeO(V+E)
SpaceO(V+E)
↑ back to top
Chapter 12 · Q126–Q132 · Shortest Paths
Shortest Paths — Dijkstra, Bellman-Ford & Floyd-Warshall
Shortest Path Algorithm Selection Guide

Unweighted graph: BFS. O(V+E). First time a node is visited = shortest path.
Weighted graph, no negative edges: Dijkstra. O((V+E) log V). Use a min-heap.
Weighted graph, negative edges (no neg cycle): Bellman-Ford. O(VE). Relax all edges V-1 times.
Negative cycle detection: Bellman-Ford Vth iteration. If relaxation still happens → negative cycle.
All-pairs shortest path: Floyd-Warshall. O(V³). DP through intermediate nodes.
DAG shortest/longest path: Topological order DP. O(V+E).

Q126 · MEDIUM Network Delay Time (Dijkstra)
GraphDijkstra
LeetCode #743
Must KnowDijkstra Template

Network of n nodes with directed weighted edges. Signal sent from node k. Return time for all nodes to receive the signal, or -1 if not all reachable. (= single-source shortest path, find max)

Decode — Single-Source Shortest Path from k; Answer = Maximum Distance

Classic Dijkstra from source k. The time for node i to receive signal = shortest path from k to i. The time for ALL nodes to receive signal = maximum shortest path distance from k.

times=[[2,1,1],[2,3,1],[3,4,1]], n=4, k=2 dist=[INF,INF,0,INF,INF] (1-indexed, k=2 has dist=0) pq={(0,2)} pop (0,2): process node 2 edge 2→1 w=1: dist[1]=0+1=1 → push (1,1) edge 2→3 w=1: dist[3]=0+1=1 → push (1,3) pq={(1,1),(1,3)} pop (1,1): process node 1 (no outgoing) pop (1,3): process node 3 edge 3→4 w=1: dist[4]=1+1=2 → push (2,4) pop (2,4): process node 4 (no outgoing) dist=[INF,1,0,1,2] max(1,0,1,2) = 2
C++ — Dijkstra with Min-Heap O((V+E) log V) int networkDelayTime(vector<vector<int>>& times, int n, int k) { vector<vector<pair<int,int>>> adj(n+1); for(auto& t:times) adj[t[0]].push_back({t[1],t[2]}); vector<int> dist(n+1,INT_MAX); priority_queue<pair<int,int>,vector<pair<int,int>>,greater<>> pq; dist[k]=0; pq.push({0,k}); while(!pq.empty()){ auto[d,u]=pq.top();pq.pop(); if(d>dist[u]) continue; // Stale entry — skip for(auto[v,w]:adj[u]) if(dist[u]+w < dist[v]){ dist[v]=dist[u]+w; pq.push({dist[v],v}); } } int ans=*max_element(dist.begin()+1, dist.end()); return ans==INT_MAX ? -1 : ans; }
TimeO((V+E) log V)
SpaceO(V+E)
Q127 · HARD Cheapest Flights Within K Stops (Bellman-Ford)
GraphBellman-Ford
LeetCode #787
Must KnowBellman-Ford k Iterations = At Most k Edges

n cities, flights with prices. Find cheapest price from src to dst with at most k stops. Return -1 if impossible. (At most k stops = at most k+1 edges)

Inputn=4,flights=[[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]] src=0,dst=3,k=1
Output700
Decode — Bellman-Ford: Relax k+1 Times = Paths Using at Most k+1 Edges

Standard Bellman-Ford relaxes V-1 times for shortest paths. Here, relax exactly k+1 times — this finds shortest paths using at most k+1 edges (k stops). Use a copy of the distance array per iteration to prevent using more edges than allowed in one iteration.

C++ — Bellman-Ford k+1 Iterations O(k×E) int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k){ vector<int> dist(n, INT_MAX); dist[src]=0; for(int i=0;i<=k;i++){ // k+1 relaxation rounds vector<int> tmp=dist; // Copy: prevent using more edges in one round for(auto& f:flights) if(dist[f[0]]!=INT_MAX && dist[f[0]]+f[2]<tmp[f[1]]) tmp[f[1]]=dist[f[0]]+f[2]; dist=tmp; } return dist[dst]==INT_MAX ? -1 : dist[dst]; }
TimeO(k×E)
SpaceO(n)
AltModified Dijkstra with state (node, stops_used)
Q128 · HARD Path With Minimum Effort (Dijkstra on Grid)
GraphDijkstraGrid
LeetCode #1631
Dijkstra Where Edge Weight = |h1-h2| and Path Weight = Max Edge

Find a path from top-left to bottom-right of a grid minimizing the maximum absolute difference in heights between consecutive cells.

Decode — Non-Standard Dijkstra: Minimize Maximum Edge Weight

Dijkstra works here because the "distance" = max absolute difference along the path, and this is monotone (adding more edges can only increase or maintain the max). Edge weight = abs(height[nr][nc] - height[r][c]). Path "distance" = max edge encountered, not sum.

C++ Solution — O(R×C × log(R×C)) int minimumEffortPath(vector<vector<int>>& h){ int R=h.size(),C=h[0].size(); vector<vector<int>> dist(R,vector<int>(C,INT_MAX)); int dx[]={0,0,1,-1},dy[]={1,-1,0,0}; priority_queue<tuple<int,int,int>,vector<tuple<int,int,int>>,greater<>> pq; dist[0][0]=0; pq.push({0,0,0}); while(!pq.empty()){ auto[effort,r,c]=pq.top();pq.pop(); if(r==R-1&&c==C-1) return effort; if(effort>dist[r][c]) continue; for(int d=0;d<4;d++){ int nr=r+dx[d],nc=c+dy[d]; if(nr>=0&&nr<R&&nc>=0&&nc<C){ int newEff=max(effort,abs(h[nr][nc]-h[r][c])); if(newEff<dist[nr][nc]){ dist[nr][nc]=newEff; pq.push({newEff,nr,nc}); } } } } return 0; }
TimeO(R×C·log(R×C))
SpaceO(R×C)
Q129 · HARD Find the City With the Smallest Number of Neighbours (Floyd-Warshall)
GraphFloyd-Warshall
LeetCode #1334
All-Pairs Shortest Path → Count Reachable Cities

Find the city with the fewest other cities reachable within a distance threshold. All-pairs shortest paths needed.

Decode — Floyd-Warshall Gives All-Pairs Shortest Paths in O(V³)

Init dist[i][i]=0, dist[i][j]=edge weight or INF. For each intermediate node k: dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]). Then count reachable cities per city and find the answer.

C++ — Floyd-Warshall O(n³) int findTheCity(int n, vector<vector<int>>& edges, int threshold){ vector<vector<long>> d(n,vector<long>(n,1e9)); for(int i=0;i<n;i++) d[i][i]=0; for(auto& e:edges){ d[e[0]][e[1]]=d[e[1]][e[0]]=e[2]; } // Floyd-Warshall for(int k=0;k<n;k++) for(int i=0;i<n;i++) for(int j=0;j<n;j++) d[i][j]=min(d[i][j], d[i][k]+d[k][j]); int ans=-1, minCount=n; for(int i=0;i<n;i++){ int cnt=0; for(int j=0;j<n;j++) if(i!=j && d[i][j]<=threshold) cnt++; if(cnt<=minCount){ minCount=cnt; ans=i; } // Largest label on tie } return ans; }
TimeO(n³)
SpaceO(n²)
Q130 · HARD Swim in Rising Water
GraphDijkstraGrid
LeetCode #778
Minimize Maximum Node Value on Path — Same as Q128 but Nodes not Edges

Grid where grid[i][j] = time when cell becomes accessible. Find the minimum time T such that there is a path from top-left to bottom-right where all cells are accessible at time T.

C++ — Dijkstra minimizing max node value on path int swimInWater(vector<vector<int>>& grid){ int n=grid.size(); vector<vector<int>> dist(n,vector<int>(n,INT_MAX)); int dx[]={0,0,1,-1},dy[]={1,-1,0,0}; priority_queue<tuple<int,int,int>,vector<tuple<int,int,int>>,greater<>> pq; dist[0][0]=grid[0][0]; pq.push({grid[0][0],0,0}); while(!pq.empty()){ auto[t,r,c]=pq.top();pq.pop(); if(r==n-1&&c==n-1) return t; if(t>dist[r][c]) continue; for(int d=0;d<4;d++){ int nr=r+dx[d],nc=c+dy[d]; if(nr>=0&&nr<n&&nc>=0&&nc<n){ int nt=max(t,grid[nr][nc]); if(nt<dist[nr][nc]){ dist[nr][nc]=nt; pq.push({nt,nr,nc}); } } } } return -1; }
TimeO(n² log n)
SpaceO(n²)
Q131 · HARD Minimum Cost to Make at Least One Valid Path in a Grid
Graph0-1 BFSDeque
LeetCode #1368
0-1 BFS: Cost 0 if Following Arrow, Cost 1 if Changing Direction

Grid has arrows (1=right,2=left,3=down,4=up). Cost 0 to follow arrow, cost 1 to change it. Find minimum cost path from top-left to bottom-right.

Decode — 0-1 BFS (Deque) for Graphs with Only 0 and 1 Edge Weights

When edge weights are only 0 or 1, use a deque instead of a priority queue. Cost 0 → push to front. Cost 1 → push to back. This gives Dijkstra-like guarantees in O(V+E) instead of O((V+E) log V).

C++ — 0-1 BFS with Deque O(R×C) int minCost(vector<vector<int>>& grid){ int R=grid.size(),C=grid[0].size(); vector<vector<int>> dist(R,vector<int>(C,INT_MAX)); // Arrow directions: 1=right,2=left,3=down,4=up int dx[]={0,0,1,-1},dy[]={1,-1,0,0}; deque<pair<int,int>> dq; dq.push_front({0,0}); dist[0][0]=0; while(!dq.empty()){ auto[r,c]=dq.front();dq.pop_front(); for(int d=0;d<4;d++){ int nr=r+dx[d],nc=c+dy[d]; if(nr<0||nr>=R||nc<0||nc>=C) continue; int cost=(grid[r][c]-1==d)?0:1; // 0 if following arrow, 1 if changing if(dist[r][c]+cost<dist[nr][nc]){ dist[nr][nc]=dist[r][c]+cost; cost==0 ? dq.push_front({nr,nc}) : dq.push_back({nr,nc}); } } } return dist[R-1][C-1]; }
TimeO(R×C)
SpaceO(R×C)
Q132 · HARD K-th Shortest Path (Yen's / Dijkstra with K Visits)
GraphDijkstra
LeetCode #2642 / CSES
Allow Each Node to Be Visited Up to K Times

Find the Kth shortest path from source to destination in a weighted directed graph (paths can repeat nodes).

Decode — Modified Dijkstra: Each Node Can Be Popped K Times

In standard Dijkstra, skip a node once visited. For Kth shortest path: allow each node to be processed up to K times. The Kth time destination is popped = Kth shortest path. Use a visit counter array.

C++ — Kth Shortest Path O(KE log V) int kthShortestPath(int n, vector<vector<pair<int,int>>>& adj, int src, int dst, int K){ vector<int> count(n+1,0); priority_queue<pair<int,int>,vector<pair<int,int>>,greater<>> pq; pq.push({0,src}); while(!pq.empty()){ auto[d,u]=pq.top();pq.pop(); count[u]++; if(count[u]>K) continue; // Only process each node K times if(u==dst&&count[u]==K) return d; // Kth time we reach dst for(auto[v,w]:adj[u]) pq.push({d+w,v}); } return -1; }
TimeO(KE log V)
SpaceO(K·V)
↑ back to top
Chapter 13 · Q133–Q140 · Union-Find & Advanced Graph
Union-Find & Advanced — DSU, MST, Bridges & SCCs
Union-Find (DSU) — The Essential Template

Two operations, both near-O(1) with path compression + union by rank:
find(x): Return the root/representative of x's component. Path compression: make every node on the path point directly to root.
unite(x,y): Merge two components. Union by rank: attach smaller tree under larger to keep height low.
When to use: Detecting cycles in undirected graphs. Counting connected components. Kruskal's MST. Dynamic connectivity problems. "Are x and y in the same group?"

Q133 · MEDIUM Union-Find (DSU) Template + Redundant Connection
Union-FindGraph
LeetCode #684
Must KnowDSU Template — Memorise This

Given a tree with one extra edge creating a cycle. Find and return the redundant edge. (= First edge that connects two nodes already in the same component)

Decode — Edge is Redundant if Both Endpoints Already in Same Component

Process edges one by one. For each edge (u,v): if find(u) == find(v) → they're already connected → this edge creates a cycle → it's the redundant edge. Otherwise unite(u, v).

edges=[[1,2],[1,3],[2,3]] parent=[0,1,2,3], rank=[0,0,0,0] edge(1,2): find(1)=1, find(2)=2 ≠ → unite. parent[2]=1 edge(1,3): find(1)=1, find(3)=3 ≠ → unite. parent[3]=1 edge(2,3): find(2)=find(1)=1, find(3)=find(1)=1 → SAME! → return [2,3]
C++ — DSU Template + Redundant Connection struct DSU { vector<int> parent, rank_; DSU(int n): parent(n), rank_(n,0){ iota(parent.begin(),parent.end(),0); } int find(int x){ if(parent[x]!=x) parent[x]=find(parent[x]); // Path compression return parent[x]; } bool unite(int x, int y){ x=find(x); y=find(y); if(x==y) return false; // Already connected! if(rank_[x]<rank_[y]) swap(x,y); // Union by rank parent[y]=x; if(rank_[x]==rank_[y]) rank_[x]++; return true; } }; vector<int> findRedundantConnection(vector<vector<int>>& edges){ DSU dsu(edges.size()+1); for(auto& e:edges) if(!dsu.unite(e[0],e[1])) return e; // Returns false = already connected = redundant return {}; }
per opO(α(n)) ≈ O(1)
SpaceO(n)
Same DSUUsed in Q134, Q135, Q136, Q137, Q138
Q134 · HARD Number of Islands II (Online Query)
Union-FindGraph
LeetCode #305 (Premium)
DSU for Dynamic Connectivity; Track Component Count

m×n grid, initially water. Process operations adding land cells one at a time. After each addition, return the current number of islands.

Decode — DSU: Add Land = Create Component, Then Merge with Adjacent Land

Maintain a DSU for land cells. When adding cell (r,c): create a new component (islandCount++). For each of 4 neighbours that are land and in a different component: unite them (islandCount--). DSU handles all merging efficiently.

C++ Solution — O(operations × α(R×C)) vector<int> numIslands2(int R, int C, vector<vector<int>>& ops){ int dx[]={0,0,1,-1},dy[]={1,-1,0,0}; DSU dsu(R*C); vector<bool> isLand(R*C,false); int islands=0; vector<int> res; for(auto& op:ops){ int r=op[0],c=op[1],id=r*C+c; if(!isLand[id]){ isLand[id]=true; islands++; for(int d=0;d<4;d++){ int nr=r+dx[d],nc=c+dy[d],nid=nr*C+nc; if(nr>=0&&nr<R&&nc>=0&&nc<C&&isLand[nid]) if(dsu.unite(id,nid)) islands--; } } res.push_back(islands); } return res; }
TimeO(Q × α(RC))
SpaceO(RC)
Q135 · HARD Minimum Spanning Tree — Kruskal's Algorithm
Union-FindGraphGreedy
CSES / LeetCode #1584
Must KnowSort Edges + DSU

Find the minimum spanning tree (MST) of a weighted undirected graph. Return the total weight of the MST.

Decode — Greedy: Always Add Cheapest Edge That Doesn't Form a Cycle

Sort all edges by weight. Process in order: if an edge connects two different components (DSU find gives different roots) → add it to MST (unite). Otherwise skip (would create cycle). Stop when n-1 edges added.

n=4, edges sorted by weight: (1,2,1),(2,3,2),(3,4,3),(1,4,10),(2,4,5) edge(1,2,w=1): find(1)≠find(2) → UNITE. MST cost=1. components: {1,2},{3},{4} edge(2,3,w=2): find(2)≠find(3) → UNITE. MST cost=3. components: {1,2,3},{4} edge(3,4,w=3): find(3)≠find(4) → UNITE. MST cost=6. n-1=3 edges added. MST total weight: 6 (skip edge 1-4 and 2-4 — not needed)
C++ — Kruskal's O(E log E) int kruskalMST(int n, vector<tuple<int,int,int>>& edges){ sort(edges.begin(),edges.end()); // Sort by weight (first element) DSU dsu(n+1); int cost=0, count=0; for(auto&[w,u,v]:edges){ if(dsu.unite(u,v)){ cost+=w; count++; if(count==n-1) break; // MST complete } } return count==n-1 ? cost : -1; // -1 if graph disconnected } // LeetCode 1584: Min Cost to Connect All Points // Build all |n*(n-1)/2| edges, apply Kruskal's int minCostConnectPoints(vector<vector<int>>& pts){ int n=pts.size(); vector<tuple<int,int,int>> edges; for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) edges.push_back({abs(pts[i][0]-pts[j][0])+abs(pts[i][1]-pts[j][1]),i,j}); return kruskalMST(n,edges); }
TimeO(E log E)
SpaceO(V)
Q136 · HARD Accounts Merge
Union-FindGraph
LeetCode #721
Must KnowDSU on Email Strings

Merge accounts with overlapping emails. Each account is [name, email1, email2...]. If two accounts share an email, they belong to the same person. Return merged accounts sorted.

Decode — Emails are Nodes; Shared Email = Union. Group by Component.

Map each email to an index. For each account, unite all emails with the first email of that account. After all unions, group emails by their root component. Sort each group and prepend the name.

C++ — DSU on Emails O(n·k·α(n)) vector<vector<string>> accountsMerge(vector<vector<string>>& accs){ unordered_map<string,int> emailId; unordered_map<string,string> emailName; int id=0; DSU dsu(10001); for(auto& acc:accs){ string& name=acc[0]; for(int i=1;i<(int)acc.size();i++){ if(!emailId.count(acc[i])){ emailId[acc[i]]=id++; emailName[acc[i]]=name; } dsu.unite(emailId[acc[1]],emailId[acc[i]]); // Unite with first email } } unordered_map<int,vector<string>> groups; for(auto&[email,idx]:emailId) groups[dsu.find(idx)].push_back(email); vector<vector<string>> res; for(auto&[root,emails]:groups){ sort(emails.begin(),emails.end()); emails.insert(emails.begin(), emailName[emails[0]]); res.push_back(emails); } return res; }
TimeO(n·k·log(n·k))
SpaceO(n·k)
Q137 · HARD Making a Large Island (DSU on Grid)
Union-FindGraphGrid
LeetCode #827
Label Islands, Then Check Each 0 Cell for Max Merge

You can change one 0 to 1. Find the size of the largest island you can create after this change.

Decode — Label Islands with DSU, Then Find Best 0 to Flip

Step 1: Use DSU to label all existing islands and record their sizes. Step 2: For each 0 cell, check 4 neighbours' island roots (use a set to avoid double-counting same island). The best flip = 1 + sum of distinct neighbour island sizes.

C++ Solution — O(R×C) int largestIsland(vector<vector<int>>& grid){ int n=grid.size(), best=0; int dx[]={0,0,1,-1},dy[]={1,-1,0,0}; DSU dsu(n*n); // Step 1: Union all existing land cells for(int i=0;i<n;i++) for(int j=0;j<n;j++) if(grid[i][j]) for(int d=0;d<4;d++){ int ni=i+dx[d],nj=j+dy[d]; if(ni>=0&&ni<n&&nj>=0&&nj<n&&grid[ni][nj]) dsu.unite(i*n+j,ni*n+nj); } // Compute island sizes vector<int> sz(n*n,0); for(int i=0;i<n;i++) for(int j=0;j<n;j++) if(grid[i][j]) sz[dsu.find(i*n+j)]++; // Step 2: Try flipping each 0 for(int i=0;i<n;i++) for(int j=0;j<n;j++) if(!grid[i][j]){ set<int> seen; int gain=1; for(int d=0;d<4;d++){ int ni=i+dx[d],nj=j+dy[d]; if(ni>=0&&ni<n&&nj>=0&&nj<n&&grid[ni][nj]){ int root=dsu.find(ni*n+nj); if(!seen.count(root)){ gain+=sz[root]; seen.insert(root); } } } best=max(best,gain); } return best==0 ? n*n : best; // If no 0 found, entire grid is one island }
TimeO(n²)
SpaceO(n²)
Q138 · HARD Bridges in a Graph (Tarjan's Algorithm)
GraphDFS
LeetCode #1192
Must KnowDiscovery Time + Low-Link Values

Find all critical connections (bridges) in a network — edges whose removal would disconnect the graph.

Decode — Bridge = Edge (u,v) Where Low[v] > disc[u]

DFS assigns each node a discovery time. low[v] = minimum discovery time reachable from v's subtree (including back edges). Edge (u,v) is a bridge if low[v] > disc[u] — v's subtree cannot reach u or above without this edge.

C++ — Tarjan's Bridge Finding O(V+E) vector<vector<int>> criticalConnections(int n, vector<vector<int>>& connections){ vector<vector<int>> adj(n), bridges; for(auto& c:connections){ adj[c[0]].push_back(c[1]); adj[c[1]].push_back(c[0]); } vector<int> disc(n,-1), low(n); int timer=0; function<void(int,int)> dfs=[&](int u, int parent){ disc[u]=low[u]=timer++; for(int v:adj[u]){ if(v==parent) continue; // Skip parent edge if(disc[v]==-1){ dfs(v,u); low[u]=min(low[u],low[v]); if(low[v]>disc[u]) bridges.push_back({u,v}); // Bridge! } else low[u]=min(low[u],disc[v]); // Back edge } }; for(int i=0;i<n;i++) if(disc[i]==-1) dfs(i,-1); return bridges; }
TimeO(V+E)
SpaceO(V+E)
Q139 · HARD Strongly Connected Components (Kosaraju's)
GraphDFS
CSES / Codeforces Edu
Two-Pass DFS: Order then Reverse Graph

Find all Strongly Connected Components (SCCs) in a directed graph. An SCC is a maximal group of nodes where every node is reachable from every other.

Decode — Kosaraju: DFS to Get Finish Order, Then DFS on Reversed Graph

Pass 1: DFS on original graph, record finish order (push to stack when DFS completes a node). Pass 2: Reverse all edges. Process nodes in reverse finish order (pop from stack). Each DFS call in pass 2 explores one complete SCC.

C++ — Kosaraju's O(V+E) int countSCCs(int n, vector<vector<int>>& adj){ vector<vector<int>> radj(n); for(int u=0;u<n;u++) for(int v:adj[u]) radj[v].push_back(u); vector<bool> vis(n,false); stack<int> order; // Pass 1: Fill order by finish time function<void(int)> dfs1=[&](int u){ vis[u]=true; for(int v:adj[u]) if(!vis[v]) dfs1(v); order.push(u); // Push after all descendants }; for(int i=0;i<n;i++) if(!vis[i]) dfs1(i); // Pass 2: DFS on reversed graph in finish order fill(vis.begin(),vis.end(),false); function<void(int)> dfs2=[&](int u){ vis[u]=true; for(int v:radj[u]) if(!vis[v]) dfs2(v); }; int sccs=0; while(!order.empty()){ int u=order.top();order.pop(); if(!vis[u]){ dfs2(u); sccs++; } // Each DFS = one SCC } return sccs; }
TimeO(V+E)
SpaceO(V+E)
Q140 · HARD Longest Path in a DAG (Critical Path)
GraphTopo SortDP
CSES / Codeforces Edu
Must KnowTopo DP: dp[v] = max(dp[u]+w) for all edges u→v

Find the longest path in a DAG (weighted or unweighted). Used in: critical path analysis, scheduling, project management.

Decode — Process Nodes in Topological Order, DP Relaxes Forward

Process nodes in topological order. For each node u: for each edge u→v, update dp[v] = max(dp[v], dp[u] + weight). The final answer is max(dp[i]). To reconstruct the path, track the predecessor that gave the maximum.

C++ — Topo DP O(V+E) long long longestPathDAG(int n, vector<vector<pair<int,int>>>& adj){ vector<int> indeg(n,0); for(int u=0;u<n;u++) for(auto&[v,w]:adj[u]) indeg[v]++; queue<int> q; for(int i=0;i<n;i++) if(indeg[i]==0) q.push(i); vector<long long> dp(n,0); while(!q.empty()){ int u=q.front();q.pop(); for(auto&[v,w]:adj[u]){ dp[v]=max(dp[v], dp[u]+w); // Relax forward if(--indeg[v]==0) q.push(v); } } return *max_element(dp.begin(),dp.end()); } // Unweighted: all edges have w=1 → longest path = DAG's "diameter" // Negative weights allowed! Just negate all weights and find shortest path.
TimeO(V+E)
SpaceO(V)
RelatedParallel Courses III (Q125) · Project Scheduling
↑ back to top