DP wali file ka graph version. Har sawaal me: problem → soch → diagram → Java code → step-by-step trace → complexity → khud try karo. Har phase apne skeleton card se shuru hota hai — wo ek template yaad kar liya toh us phase ke saare sawaal usi ke knobs hain.
Ye chaar sawaal "sawaal" nahi hain, ye alphabet hain. Aage ke 43 questions me se har ek in chaar ka koi na koi mixture hai. Isliye yahan jaldi mat karna.
Phase 0 · skeleton
Graph ke har problem me sirf teen cheezein decide karni hoti hain:
1. Node kya hai? Kabhi city, kabhi grid ka cell, kabhi ek word, kabhi ek state (row, col, k). Ye pehchan lo, aadha kaam ho gaya.
2. Edge kya hai? Kaun-kaun se do nodes "juday" hue hain. Grid me 4 padosi, words me "ek letter ka farak", cities me diya hua list.
3. Chalna kaise hai? BFS (layer by layer → shortest steps) ya DFS (ek raasta poora khatam karo → reachability, components, ordering).
Q01
Graph ki vocabulary
theorymust-know
Graph = nodes (vertices, points) + edges (lines jo do nodes ko jodti hain). Bas itna. Tree bhi ek graph hi hai — ek special graph jisme cycle nahi hoti aur sab connected hota hai.
5 nodes, 5 edges — undirected
Shabd jo baar-baar aayenge
Shabd
Matlab
Undirected
Edge dono taraf chalti hai. 1—2 hai toh 1 se 2 bhi ja sakte ho, 2 se 1 bhi.
Directed
Edge ek taraf. 1→2 ka matlab 2→1 nahi. (Course prerequisites, task dependencies)
Weighted
Har edge pe ek number — distance, cost, time.
Degree
Node se kitni edges lagi hain. Undirected me: sum of degrees = 2 × edges.
Path
Nodes ki sequence jahan har consecutive pair me edge ho.
Cycle
Path jo wahin lautkar aa jaye jahan se shuru hui thi.
Component
Ek "island" of nodes. Graph ke do tukde alag ho sakte hain — ye baat 90% log bhool jaate hain.
DAG
Directed Acyclic Graph — directed hai aur cycle nahi hai. Topological sort sirf isi pe chalta hai.
Sabse bada trap: question "a graph" bolta hai, tum maan lete ho ek hi connected tukda hai. Nahi. Isliye har traversal ka driver loop aisa hota hai: for (i = 0; i < n; i++) if (!vis[i]) dfs(i); — Q5 (Provinces) ka poora sawaal yahi ek line hai.
Nodes 0-indexed ya 1-indexed?
Question padho. LeetCode 0-indexed deta hai, GFG/CP aksar 1-indexed. Agar 1-indexed hai toh arrays n+1 size ke banao. Ek off-by-one yahan poora solution le doobti hai.
Khud try karo
Upar wale diagram me har node ka degree likho. Sum check karo — 10 aana chahiye.
Usme ek cycle dhoondo. (Hint: 1→2→4→3→1)
Agar edge 4—5 hata do, toh kitne components banenge?
Q02
Representation: matrix vs list
theorysetup code
Code me graph ko store karne ke do tareeke. Interview me 99% baar adjacency list chahiye.
1 · Adjacency Matrix
adj[u][v] = 1 agar u aur v ke beech edge hai. n×n ka 2D array.
Java · matrix
int[][] adj = newint[n][n];
for (int[] e : edges) {
adj[e[0]][e[1]] = 1;
adj[e[1]][e[0]] = 1; // ye line sirf undirected me
}
Space O(n²). n = 105 pe ye 1010 cells — memory phat jayegi. Isliye matrix sirf tab jab n chhota ho (≤ 1000) ya question hi matrix de raha ho (Q5 Provinces, Q33 Floyd-Warshall).
2 · Adjacency List — default choice
Har node ke saamne uske padosiyon ki list. Space O(n + 2E).
Q1 wale graph ki adjacency list
Java · adjacency list (yaad kar lo, har question me likhoge)
List<List<Integer>> adj = newArrayList<>();
for (int i = 0; i < n; i++) adj.add(newArrayList<>());
for (int[] e : edges) {
adj.get(e[0]).add(e[1]);
adj.get(e[1]).add(e[0]); // undirected hi me
}
Weighted graph
Neighbour ke saath weight bhi rakhna hai. Do options:
Java · weighted (int[] pair — sabse tez)
List<int[]>[] adj = newList[n];
for (int i = 0; i < n; i++) adj[i] = newArrayList<>();
for (int[] e : edges) { // e = {u, v, wt}
adj[e[0]].add(newint[]{e[1], e[2]});
adj[e[1]].add(newint[]{e[0], e[2]});
}
// use: for (int[] nb : adj[u]) { int v = nb[0], wt = nb[1]; ... }
Space
matrix O(n²) list O(n+2E)
"u-v edge hai?"
matrix O(1) list O(degree)
"u ke padosi do"
matrix O(n) list O(degree)
Kab matrix
n ≤ 1000, ya dense, ya Floyd-Warshall
Note: traversal me tum hamesha "u ke padosi do" poochte ho, kabhi "u-v edge hai?" nahi. Isiliye list default hai — matrix pe BFS O(n²) ho jata hai, list pe O(n+E).
Khud try karo
Edges {{0,1},{0,2},{1,3},{2,3},{3,4}}, n=5. Adjacency list haath se likho.
Directed bana do — kaunsi line hategi? Ab node 4 ki list me kya hoga?
Q03
BFS — level by level
traversalqueueshortest steps
BFS = Breadth First Search. Ek pathar paani me girao — lehrein circle me phailti hain. Pehle 1 step door ke saare, phir 2 step door ke saare. Isiliye unweighted graph me shortest path hamesha BFS deta hai.
Tool: Queue (FIFO — jo pehle aaya wo pehle nikla).
Source = 1. Mint edges = BFS tree. Node 2—4 wali edge use hi nahi hui.
Java · BFS template
void bfs(int src, List<List<Integer>> adj, boolean[] vis) {
Queue<Integer> q = newLinkedList<>();
q.add(src);
vis[src] = true; // MARK KARO PUSH KE WAQTwhile (!q.isEmpty()) {
int node = q.poll();
System.out.print(node + " ");
for (int nb : adj.get(node)) {
if (!vis[nb]) {
vis[nb] = true;
q.add(nb);
}
}
}
}
Sabse common bug:vis[nb] = true ko push ke waqt nahi, pop ke waqt karna. Tab ek node queue me 5 baar ghus jata hai, TLE ya galat count. Rule: jis waqt queue me daala, usi waqt visited.
Trace — source 1
steppopqueue (baad me)kya hua
0—1src push, vis={1}
11231 ke padosi 2,3 — dono naye
22342 ke padosi 1(seen), 4(naya)
3343 ke padosi 1,4 — dono already vis
4455 naya
55— emptykhatam. order: 1 2 3 4 5
Level count chahiye toh — "size snapshot" trick
Ye Q8 (Rotten Oranges), Q13 (Word Ladder), Q25 me har jagah aayega. Loop ke shuru me queue ka size le lo — utne pop karna ek level hai.
Java · level-wise BFS
int level = 0;
while (!q.isEmpty()) {
int sz = q.size(); // is level me kitne hain, snapshotfor (int i = 0; i < sz; i++) {
int node = q.poll();
for (int nb : adj.get(node)) {
if (!vis[nb]) { vis[nb] = true; q.add(nb); }
}
}
level++; // ek poori layer khatam
}
Data structure
Queue — FIFO
Time
O(n + 2E)
Space
O(n) — queue + vis
Kab use karo
"minimum steps", "shortest", "kitne seconds me"
Khud try karo
Source 5 se BFS ka trace tape khud banao. Order kya aayega?
ArrayDeque vs LinkedList — kaunsa faster hai aur kyun? (dono Queue implement karte hain)
Q04
DFS — gehrai me
traversalrecursionstack
DFS = Depth First Search. Bhool-bhulaiya me ek raasta pakdo aur jab tak deewar na aaye chalte raho. Deewar aa gayi? Peeche lauto (backtrack) aur agla raasta pakdo.
Tool: Recursion (jo andar-andar call stack use karta hai).
1→2→4→3 (dead end, backtrack) →5. DFS tree BFS se alag banta hai.
Java · DFS recursive template
void dfs(int node, List<List<Integer>> adj, boolean[] vis) {
vis[node] = true;
System.out.print(node + " ");
for (int nb : adj.get(node)) {
if (!vis[nb]) dfs(nb, adj, vis);
}
}
Recursion stack ka trace
stepcall/returnstack (neeche→upar)kya hua
1dfs(1)1print 1, padosi 2 pe jao
2dfs(2)12print 2, padosi 1 seen, 4 pe jao
3dfs(4)124print 4, padosi 2 seen, 3 pe jao
4dfs(3)1243print 3, sab padosi seen → dead end
5return ↓1244 pe wapas, agla padosi 5
6dfs(5)1245print 5, dead end
7sab return— emptyorder: 1 2 4 3 5
Iterative DFS (stack se) — kab chahiye
Jab n bada ho (105+) aur recursion depth se StackOverflow ka dar ho. Java me default stack ~104 depth handle karta hai.
Java · DFS with explicit stack
Deque<Integer> st = newArrayDeque<>();
st.push(src);
while (!st.isEmpty()) {
int node = st.pop();
if (vis[node]) continue; // yahan check, kyunki duplicate push ho sakte hain
vis[node] = true;
System.out.print(node + " ");
for (int nb : adj.get(node)) if (!vis[nb]) st.push(nb);
}
Java me deep recursion ka jugaad: agar depth 105 tak ja sakti hai, poora kaam ek bade stack wale thread me chala do — new Thread(null, task, "main", 1<<26).start();
BFS vs DFS — kaunsa kab
BFS
DFS
Structure
Queue (FIFO)
Recursion / Stack (LIFO)
Order
layer by layer
ek raasta poora, phir backtrack
Shortest path (unweighted)
haan, guaranteed
nahi
Components ginna
chalega
chalega (aur chhota code)
Cycle detect
chalega
directed graph me DFS zaroori
Topological sort
Kahn
DFS + reverse
Space worst case
O(width)
O(depth)
Khud try karo
Agar adjacency list me har node ke padosi descending order me hote, toh DFS ka output kya hota?
Iterative DFS ka output recursive se alag aa sakta hai — kyun? (hint: stack me kaunsa padosi upar aata hai)
Ek disconnected graph banao (2 components) aur dono traversals ka driver loop likho.
Phase 1
Grid & Components
Yahan graph tumhe diya nahi jata — grid diya jata hai, aur tumhe usme graph dekhna padta hai. Har cell ek node, har padosi cell ek edge. Ye phase interviews aur OAs me sabse zyada poocha jata hai.
Phase 1 · skeleton
Poore phase ka ek hi dhaancha hai — driver loop + flood:
for (har cell/node i) if (!vis[i] && relevant(i)) { count++; flood(i); }
flood = BFS ya DFS, jo poore component ko visited mark kar deta hai. Sirf teen knobs badalte hain:
relevant(i) — kaunsa cell "land" hai? padosi — 4-dir ya 8-dir? flood ke andar kya count/collect karna hai?
Grid ka padosi code — ek baar seekh lo, 8 questions me chalega:
int[] dr = {-1, 0, 1, 0}; // up, right, down, leftint[] dc = { 0, 1, 0,-1};
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < n && nc >= 0 && nc < m && !vis[nr][nc] && grid[nr][nc] == '1') {
// yahan kaam
}
}
8-direction chahiye toh: dr = {-1,-1,-1,0,0,1,1,1}, dc = {-1,0,1,-1,1,-1,0,1}.
Ye literally Q1 wala trap ka sawaal hai. "Province" = "connected component". Ek node se DFS chalao — jitne tak pahuncha, sab ek hi province. Phir agla un-visited node dhoondo, count++ karo, phir DFS. Bas.
Matrix diya hai isliye pehle adjacency list bana lo (ya matrix pe hi chalo — n chhota hai, 200 tak).
Akela node bhi ek poora province hai — ye edge case mat bhoolna
Java · DFS
publicint findCircleNum(int[][] isConnected) {
int n = isConnected.length;
boolean[] vis = newboolean[n];
int count = 0;
for (int i = 0; i < n; i++) {
if (!vis[i]) { // naya component mila
count++;
dfs(i, isConnected, vis);
}
}
return count;
}
privatevoid dfs(int u, int[][] g, boolean[] vis) {
vis[u] = true;
for (int v = 0; v < g.length; v++) {
if (g[u][v] == 1 && !vis[v]) dfs(v, g, vis);
}
}
relevant(i)
!vis[i]
padosi
g[u][v] == 1
flood me
kuch nahi — bas mark
Complexity
O(n²) time, O(n) space
Trap:count++ DFS ke andar mat likhna. Wo har node pe badhega, har component pe nahi. Sirf driver loop me.
Khud try karo
Yahi sawaal BFS se likho.
Q38 (Make Network Connected) me yahi count kaam aata hai — answer components - 1 hota hai. Kyun, socho.
Q06
Number of Islands
LC 200gridflood fill
Problem:'1' = land, '0' = water. 4-directionally juda hua land ek island hai. Kitne islands?
Soch
Bilkul Q5, bas node ab cell hai aur edge "padosi cell jo bhi land ho". Ek land cell mila jo abhi tak visited nahi → naya island, count++, aur us poore island ko flood karke visited mark kar do.
Diagonal se juda hua land alag island hai (4-dir rule)
Java · BFS flood
publicint numIslands(char[][] grid) {
int n = grid.length, m = grid[0].length, count = 0;
boolean[][] vis = newboolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (!vis[i][j] && grid[i][j] == '1') {
count++;
bfs(i, j, grid, vis);
}
}
}
return count;
}
privatevoid bfs(int r, int c, char[][] grid, boolean[][] vis) {
int n = grid.length, m = grid[0].length;
int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
Queue<int[]> q = newLinkedList<>();
q.add(newint[]{r, c});
vis[r][c] = true;
while (!q.isEmpty()) {
int[] cell = q.poll();
for (int k = 0; k < 4; k++) {
int nr = cell[0] + dr[k], nc = cell[1] + dc[k];
if (nr >= 0 && nr < n && nc >= 0 && nc < m
&& !vis[nr][nc] && grid[nr][nc] == '1') {
vis[nr][nc] = true;
q.add(newint[]{nr, nc});
}
}
}
}
vis array bachana ho toh: visited land ko '0' me badal do (grid ko destroy karke). Space O(1) extra ho jayega. Interview me pooch lo ki grid modify kar sakte hain ya nahi.
Trace — pehla island (0,0) se
steppopqueuenaye padosi
0—(0,0)count = 1
1(0,0)(0,1)(1,0)right aur down dono land
2(0,1)(1,0)(0,2)=0, (1,1)=0 — kuch nahi
3(1,0)emptyisland 1 poora ho gaya (3 cells)
relevant(cell)
grid == '1' && !vis
padosi
4-dir
Time
O(n×m)
Space
O(n×m)
Khud try karo
8-directional version (GFG pe yahi poochte hain) — sirf dr/dc badalna hai.
Sabse bade island ka size return karo (LC 695).
Q07
Flood Fill
LC 733grid
Problem: Paint bucket tool. (sr, sc) se shuru karke, us cell ke original colour wale saare connected cells ko newColor me badal do.
Soch
Q6 hi hai — sirf "land" ki definition badal gayi. Land = "wahi colour jo starting cell ka tha". Aur mark karne ke bajaye colour bhar rahe ho.
Java · DFS in-place
publicint[][] floodFill(int[][] image, int sr, int sc, int color) {
int old = image[sr][sc];
if (old == color) return image; // *** ye line na ho toh infinite loop ***
dfs(image, sr, sc, old, color);
return image;
}
privatevoid dfs(int[][] img, int r, int c, int old, int nw) {
if (r < 0 || r >= img.length || c < 0 || c >= img[0].length) return;
if (img[r][c] != old) return;
img[r][c] = nw; // yahi "visited" ka kaam bhi kar raha hai
dfs(img, r - 1, c, old, nw);
dfs(img, r + 1, c, old, nw);
dfs(img, r, c - 1, old, nw);
dfs(img, r, c + 1, old, nw);
}
Ye interview me sabse zyada miss hone wali line hai: agar newColor == oldColor hai aur tum guard nahi lagate, toh cell repaint hota hai lekin "badla nahi" jaisa dikhta hai → recursion kabhi rukti nahi → StackOverflow.
Style note: yahan boundary check function ke andar hai (call karke check), Q6 me call se pehle tha. Dono theek hain — ek style chuno aur usi pe atke raho, mix karoge toh bug aayega.
Khud try karo
Iterative BFS version likho.
Guard line hata ke color = image[sr][sc] ke saath chala ke dekho — kya hota hai?
Q08
Rotten Oranges
LC 994multi-source BFSlevels
Problem:0 = khaali, 1 = fresh orange, 2 = rotten. Har second me rotten orange apne 4 padosi fresh oranges ko rotten kar deta hai. Kitne seconds me sab rotten? Agar koi fresh reh jaye toh -1.
Soch — sabse important idea of this phase
Yahan ek source nahi, kai sources hain — saare rotten oranges ek saath sadaate hain. Alag-alag BFS chalane ki zaroorat nahi. Saare sources ko shuru me hi queue me daal do, phir normal BFS. Ye multi-source BFS hai.
Kyun sahi hai? Kyunki BFS layer-by-layer badhta hai — layer 1 me wo saare cells aayenge jo kisi bhi source se 1 step door hain. Yani har cell ko uske sabse nazdeek source se distance milta hai. Bilkul wahi jo chahiye.
Multi-source BFS: 2 rotten oranges = 2 starting points, ek hi BFS
Java · multi-source BFS with level counting
publicint orangesRotting(int[][] grid) {
int n = grid.length, m = grid[0].length;
Queue<int[]> q = newLinkedList<>();
int fresh = 0;
// STEP 1: saare sources queue me, aur fresh ginofor (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
if (grid[i][j] == 2) q.add(newint[]{i, j});
elseif (grid[i][j] == 1) fresh++;
}
if (fresh == 0) return0; // *** edge case: koi fresh hi nahi ***int time = 0;
int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
// STEP 2: level-wise BFSwhile (!q.isEmpty()) {
int sz = q.size();
boolean sadaAny = false;
for (int i = 0; i < sz; i++) {
int[] cur = q.poll();
for (int k = 0; k < 4; k++) {
int nr = cur[0] + dr[k], nc = cur[1] + dc[k];
if (nr >= 0 && nr < n && nc >= 0 && nc < m && grid[nr][nc] == 1) {
grid[nr][nc] = 2; // rotten = visited
fresh--;
sadaAny = true;
q.add(newint[]{nr, nc});
}
}
}
if (sadaAny) time++; // is second me kuch sada tabhi ginte hain
}
return fresh == 0 ? time : -1;
}
Trace
tlevel sizeis second me sadefresh bacha
02 sources(0,0)(0,2)shuruaat, fresh = 5
12(0,1)(1,0)(0,3)fresh = 2
23(1,1)(1,3)fresh = 0 → answer 2
Do traps: 1. time++ bina sadaAny check ke — aakhri level me kuch nahi sadta, par time badh jata hai → answer 1 zyada. (Alternative fix: time - 1 return karo, par tab fresh=0 case tootega. Flag saaf hai.) 2. Fresh count track na karna — tab pata hi nahi chalega ki koi orange bacha reh gaya (jo kisi rotten se juda hi nahi tha).
Sources
saare cells jinme 2 hai
visited
grid[r][c] = 2 karke
Answer
BFS levels ki count
Time / Space
O(n×m) / O(n×m)
Khud try karo
[[0,2]] pe chala ke dekho — answer 0 aana chahiye.
[[2,1,1],[0,1,1],[1,0,1]] — answer -1 kyun hai?
Q09
0/1 Matrix — nearest 0 ki distance
LC 542multi-source BFSdistance array
Problem: Binary matrix diya hai. Har cell ke liye nazdeek se nazdeek 0 ki distance batao.
Soch — ulta chalo
Naive soch: har 1 se BFS chalao. O((nm)²) — TLE.
Ulta karo: har 1 se zeros dhoondhne ke bajaye, saare zeros se ek saath BFS chalao. Jo cell jis level pe pahuncha, wahi uska answer. Yahi Q8 ka multi-source pattern hai — sirf ab level number ko store bhi kar rahe ho.
Java
publicint[][] updateMatrix(int[][] mat) {
int n = mat.length, m = mat[0].length;
int[][] dist = newint[n][m];
boolean[][] vis = newboolean[n][m];
Queue<int[]> q = newLinkedList<>();
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (mat[i][j] == 0) { q.add(newint[]{i, j, 0}); vis[i][j] = true; }
int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
while (!q.isEmpty()) {
int[] cur = q.poll();
int r = cur[0], c = cur[1], d = cur[2];
dist[r][c] = d;
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < n && nc >= 0 && nc < m && !vis[nr][nc]) {
vis[nr][nc] = true;
q.add(newint[]{nr, nc, d + 1});
}
}
}
return dist;
}
Yahan level counter ki jagah distance queue me hi carry ho rahi hai (int[]{r, c, d}). Ye style Q28, Q30 me bhi kaam aayegi — jab har node ke saath koi extra state le jaani ho.
Ek 3×3 pe result
input
output (dist)
0 0 0 0 1 0 1 1 1
0 0 0 0 1 0 1 2 1
Beech wala 1 apne upar wale 0 se 1 door hai. Neeche beech wala (2,1) apne har taraf 1 se ghira hai — nazdeek 0 do steps door hai.
Khud try karo
Zeros wale cells ko dist = 0 milna already guarantee hai — kyun?
Ye DP se bhi hota hai (do pass: top-left→bottom-right, phir ulta). Try karo — O(nm) same, par BFS zyada natural hai.
Q10
Surrounded Regions
LC 130boundary DFSreverse thinking
Problem: Board me 'X' aur 'O'. Jo bhi 'O' region charon taraf se 'X' se ghira hua hai, use 'X' me badal do.
Soch — seedha mat socho, ulta socho
Seedha approach: har O region check karo ki wo ghira hua hai ya nahi. Complicated.
Ulta: ek O region tabhi bachta hai jab wo boundary tak pahunch sakta ho. Toh:
Boundary ke saare 'O' se DFS chalao → jo bhi mila, wo "safe" hai, mark kar do.
Ab poore board pe ghoomo: jo 'O' safe nahi hai, use 'X' bana do.
Ye "boundary se ulta chalo" trick Q11 me bhi lagegi, aur ek pattern hai jo har jagah kaam aata hai — "jo bachna chahiye use pehle dhoondo, baaki sab maar do."
(3,2) last row pe hai → boundary → uska poora region safe
Java
publicvoid solve(char[][] board) {
int n = board.length, m = board[0].length;
boolean[][] safe = newboolean[n][m];
// pehli aur aakhri columnfor (int i = 0; i < n; i++) {
if (board[i][0] == 'O' && !safe[i][0]) dfs(i, 0, board, safe);
if (board[i][m-1] == 'O' && !safe[i][m-1]) dfs(i, m-1, board, safe);
}
// pehli aur aakhri rowfor (int j = 0; j < m; j++) {
if (board[0][j] == 'O' && !safe[0][j]) dfs(0, j, board, safe);
if (board[n-1][j] == 'O' && !safe[n-1][j]) dfs(n-1, j, board, safe);
}
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (board[i][j] == 'O' && !safe[i][j]) board[i][j] = 'X';
}
privatevoid dfs(int r, int c, char[][] b, boolean[][] safe) {
int n = b.length, m = b[0].length;
safe[r][c] = true;
int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < n && nc >= 0 && nc < m
&& !safe[nr][nc] && b[nr][nc] == 'O') {
dfs(nr, nc, b, safe);
}
}
}
Khud try karo
1×n aur n×1 board pe kya hoga? (Har cell boundary pe hai → kuch nahi badlega)
Corner cells do baar DFS ka source ban sakte hain — kya problem hai? (Nahi, !safe guard sambhaal leta hai)
Q11
Number of Enclaves
LC 1020boundary DFS
Problem:1 = land. Kitne land cells aise hain jahan se tum grid ke bahar nikal hi nahi sakte (chalte hue 4-dir me)?
Soch
Bilkul Q10 ka clone. Boundary ke land se BFS/DFS → wo sab "escape kar sakte hain". Baaki jo land bacha, wahi enclave hai — unhe gin lo.
Java · BFS
publicint numEnclaves(int[][] grid) {
int n = grid.length, m = grid[0].length;
boolean[][] vis = newboolean[n][m];
Queue<int[]> q = newLinkedList<>();
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if ((i == 0 || j == 0 || i == n-1 || j == m-1) && grid[i][j] == 1) {
q.add(newint[]{i, j});
vis[i][j] = true;
}
int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
while (!q.isEmpty()) {
int[] cur = q.poll();
for (int k = 0; k < 4; k++) {
int nr = cur[0] + dr[k], nc = cur[1] + dc[k];
if (nr >= 0 && nr < n && nc >= 0 && nc < m
&& !vis[nr][nc] && grid[nr][nc] == 1) {
vis[nr][nc] = true;
q.add(newint[]{nr, nc});
}
}
}
int count = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (grid[i][j] == 1 && !vis[i][j]) count++;
return count;
}
Q10 vs Q11 side-by-side rakho. Bilkul ek hi code hai. Sirf aakhir me: Q10 'X' likhta hai, Q11 count++ karta hai. Yahi hai "knob badalna".
Khud try karo
LC 1254 (Number of Closed Islands) — wahi cheez, par 0 land hai aur count islands ka hai, cells ka nahi.
Q12
Number of Distinct Islands
LC 694shape hashingnormalization
Problem: Q6 jaise islands gino, par same shape wale islands ek hi count honge (bina rotate/flip ke, sirf translate).
Soch — shape ko "canonical" banana
Do islands same shape ke hain ya nahi — ye kaise pata karein? Har island ke cells ke absolute coordinates alag honge. Toh unhe base cell ke relative me convert karo.
Agar island ka pehla cell (r0, c0) hai, toh har cell (r, c) ko (r - r0, c - c0) store karo. Ab do same-shape islands ka relative list bilkul identical aayega — usko HashSet me daal do.
Alag jagah, same normalized signature → ek hi distinct island
Java
publicint countDistinctIslands(int[][] grid) {
int n = grid.length, m = grid[0].length;
boolean[][] vis = newboolean[n][m];
Set<String> shapes = newHashSet<>();
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (!vis[i][j] && grid[i][j] == 1) {
StringBuilder sb = newStringBuilder();
dfs(i, j, i, j, grid, vis, sb); // base = (i, j)
shapes.add(sb.toString());
}
return shapes.size();
}
privatevoid dfs(int r, int c, int r0, int c0, int[][] g,
boolean[][] vis, StringBuilder sb) {
vis[r][c] = true;
sb.append(r - r0).append(',').append(c - c0).append(' '); // relativeint[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < g.length && nc >= 0 && nc < g[0].length
&& !vis[nr][nc] && g[nr][nc] == 1) {
dfs(nr, nc, r0, c0, g, vis, sb);
}
}
}
Trap: DFS ka visit order deterministic hona chahiye. Kyunki dr/dc ka order fixed hai aur base same tareeke se chuna gaya hai, do identical shapes ki string bhi identical banegi. Agar tum Set<String> ki jagah cells ko unordered set me daloge toh bhi chalega, par string zyada seedha hai.
Alternative signature: path ko directions me encode karo — "U", "D", "L", "R", aur backtrack pe "B". "B" zaroori hai, warna alag shapes ki same string ban sakti hai.
Khud try karo
LC 711 (Distinct Islands II) — ab rotation aur reflection bhi same maane jate hain. Signature kaise banaoge? (Hint: 8 transformations me se lexicographically smallest chuno)
Q13
Word Ladder I
LC 127implicit graphBFS shortest
Problem:beginWord se endWord tak pahuncho, ek baar me ek hi letter badal sakte ho, aur har beech ka word wordList me hona chahiye. Minimum kitne words ki sequence chahiye?
Soch — graph diya hi nahi hai, tumhe banana hai
Ye phase ka sabse important conceptual jump hai. Yahan koi grid nahi, koi edges list nahi. Phir bhi ye graph problem hai:
Node = ek word
Edge = do words ke beech agar exactly ek letter ka farak hai
"Minimum steps" + unweighted → BFS
Edges pehle se bana ke rakhne ki zaroorat nahi — BFS ke waqt "on the fly" generate karo. Ye implicit graph kehlata hai.
Padosi kaise banaye
Current word ki har position pe 'a' se 'z' tak har letter try karo. Jo bhi naya word wordSet me mila — wo padosi hai.
Cost: word length L, alphabet 26 → per word O(26 × L) neighbours, aur set lookup O(L). Total O(N × 26 × L²).
Java
publicint ladderLength(String beginWord, String endWord, List<String> wordList) {
Set<String> set = newHashSet<>(wordList);
if (!set.contains(endWord)) return0; // *** edge case ***Queue<String> q = newLinkedList<>();
q.add(beginWord);
set.remove(beginWord); // visited ka kaam set hi kar raha haiint steps = 1;
while (!q.isEmpty()) {
int sz = q.size();
for (int i = 0; i < sz; i++) {
String word = q.poll();
if (word.equals(endWord)) return steps;
char[] arr = word.toCharArray();
for (int pos = 0; pos < arr.length; pos++) {
char original = arr[pos];
for (char ch = 'a'; ch <= 'z'; ch++) {
if (ch == original) continue;
arr[pos] = ch;
String next = newString(arr);
if (set.contains(next)) {
set.remove(next); // dobara visit na ho
q.add(next);
}
}
arr[pos] = original; // *** restore karo ***
}
}
steps++;
}
return0;
}
Trace — hit → cog, list = [hot, dot, dog, lot, log, cog]
steplevelqueuekya bana
11hitstart
22hoth_t → hot (set me hai)
33dotlot_ot pe d aur l dono milte hain
44doglogdo_ → dog, lo_ → log
55cogendWord mila → return 5
Teen traps: 1. arr[pos] = original restore karna bhool jaana — agli positions corrupt word pe chalengi. 2. endWord list me hai ya nahi — nahi hai toh answer 0. 3. steps 1 se shuru hota hai (beginWord bhi count hota hai), 0 se nahi.
Node
ek word
Edge
ek letter ka farak
visited
set se remove karke
Time
O(N × 26 × L²)
Khud try karo
Word Ladder II (LC 126) — saare shortest paths return karne hain. Bahut hard hai; abhi chhod do, Q27 (path printing) ke baad wapas aana.
Bidirectional BFS — dono taraf se chalao, beech me mil jao. Kitna faster? (roughly bd/2 vs bd)
Phase 2
Cycle & Bipartite
Traversal ab sirf "ghoomna" nahi raha — ab ghoomte waqt kuch check karna hai. Ek hi idea ke do roop: undirected me "parent ko chhod ke koi visited mila?" aur directed me "abhi ke rraste pe hi wapas aa gaye?"
Phase 2 · skeleton
Cycle ka matlab: traversal ke dauran ek aisa node mila jo pehle se visited hai. Par "pehle se visited" har baar cycle nahi hota — isliye ek extra condition chahiye:
Undirected: visited hai aur mera parent nahi hai → cycle. (Parent ko ignore karna padta hai kyunki edge dono taraf hai.)
Directed: visited hai aur abhi wale recursion path pe hai (pathVis) → cycle. Sirf vis kaafi nahi.
Bipartite: wahi traversal, par visited node ka colour mere jaisa nikla → odd cycle → not bipartite.
Q14
Cycle in Undirected — BFS
GFGparent tracking
Problem: Undirected graph me cycle hai ya nahi?
Soch
BFS chalao. Har node ke saath uska parent bhi queue me carry karo. Ab jab kisi padosi nb pe pahuncho:
nb visited nahi → normal, push karo (parent = current node)
nb visited hai aurnb != parent → cycle mil gaya
nb == parent → ignore, ye toh wahi edge hai jisse aaye the
Source 0. BFS 1 aur 3 dono ko level 1 pe daalta hai; 2 pe aakar 3 mil jata hai.
Java · BFS
publicboolean isCycle(int V, List<List<Integer>> adj) {
boolean[] vis = newboolean[V];
for (int i = 0; i < V; i++) // disconnected components!if (!vis[i] && bfsCheck(i, adj, vis)) returntrue;
returnfalse;
}
privateboolean bfsCheck(int src, List<List<Integer>> adj, boolean[] vis) {
Queue<int[]> q = newLinkedList<>(); // {node, parent}
q.add(newint[]{src, -1});
vis[src] = true;
while (!q.isEmpty()) {
int[] cur = q.poll();
int node = cur[0], parent = cur[1];
for (int nb : adj.get(node)) {
if (!vis[nb]) {
vis[nb] = true;
q.add(newint[]{nb, node});
} elseif (nb != parent) {
returntrue; // visited + parent nahi = cycle
}
}
}
returnfalse;
}
Trap: driver loop bhool jaana. Cycle kisi doosre component me ho sakta hai. Aur self-loop (u—u) ya multi-edge ho toh ye code bhi cycle bata dega — jo sahi hi hai.
Khud try karo
Tree pe chala ke dekho — false aana chahiye. Kyun? (Tree me edges = V-1, cycle possible hi nahi)
Q15
Cycle in Undirected — DFS
GFGrecursion
Wahi logic, chhota code. Parent recursion parameter ban jata hai.
Java · DFS
publicboolean isCycle(int V, List<List<Integer>> adj) {
boolean[] vis = newboolean[V];
for (int i = 0; i < V; i++)
if (!vis[i] && dfs(i, -1, adj, vis)) returntrue;
returnfalse;
}
privateboolean dfs(int node, int parent, List<List<Integer>> adj, boolean[] vis) {
vis[node] = true;
for (int nb : adj.get(node)) {
if (!vis[nb]) {
if (dfs(nb, node, adj, vis)) returntrue; // *** return propagate karo ***
} elseif (nb != parent) {
returntrue;
}
}
returnfalse;
}
Sabse common bug:dfs(nb, node, adj, vis); likh dena bina if (...) return true; ke. Tab recursion cycle dhoond leta hai lekin answer upar tak pahunchta hi nahi, aur function false return kar deta hai.
Parallel edges wala corner case: agar graph me u—v do baar hai, toh ye nb != parent check use cycle nahi maanega (galat). Fix: parent ki jagah edge-id track karo. Interview me poocha jaye tabhi mention karo.
Q16
Bipartite Graph
LC 7852-colouringodd cycle
Problem: Kya graph ko do colours se aise rang sakte ho ki koi bhi edge ke dono ends ka colour alag ho?
Soch
BFS/DFS chalao, source ko colour 0 do. Har padosi ko opposite colour do. Agar kisi padosi ka colour pehle se mere hi jaisa nikla → not bipartite.
Ek theorem yaad rakho: graph bipartite hai ⇔ usme koi odd length cycle nahi hai. Even cycle (4, 6, ...) bipartite hoti hai, odd (3, 5, ...) nahi.
Odd cycle me do padosi same colour pe aa hi jaate hain
Java · BFS colouring
publicboolean isBipartite(int[][] graph) {
int n = graph.length;
int[] color = newint[n];
Arrays.fill(color, -1); // -1 = abhi rangaa nahifor (int i = 0; i < n; i++) {
if (color[i] != -1) continue;
Queue<Integer> q = newLinkedList<>();
q.add(i);
color[i] = 0;
while (!q.isEmpty()) {
int node = q.poll();
for (int nb : graph[node]) {
if (color[nb] == -1) {
color[nb] = 1 - color[node]; // ulta colour
q.add(nb);
} elseif (color[nb] == color[node]) {
returnfalse; // conflict
}
}
}
}
returntrue;
}
Java · DFS version (same idea)
privateboolean dfs(int node, int col, int[][] g, int[] color) {
color[node] = col;
for (int nb : g[node]) {
if (color[nb] == -1) {
if (!dfs(nb, 1 - col, g, color)) returnfalse;
} elseif (color[nb] == col) returnfalse;
}
returntrue;
}
Trace — graph = [[1,3],[0,2],[1,3],[0,2]]
popcolourqueuepadosi check
00131 aur 3 ko colour 1 mila
11320 ok (0≠1), 2 ko colour 0
3120 ok, 2 ok (0≠1)
20empty1,3 dono colour 1 — ok → true
Interview me kaam ki baat: "team ko do groups me baanto taaki dushman ek group me na hon" — ye bipartite check hi hai. LC 886 (Possible Bipartition) exactly yahi hai, bas graph khud banana padta hai.
Khud try karo
LC 886 solve karo — dislikes list se adjacency list banao, phir yahi code.
Disconnected bipartite graph pe check karo — driver loop ke bina kya tootega?
Q17
Cycle in Directed — DFS
GFGpathViscore concept
Problem: Directed graph me cycle hai ya nahi?
Soch — yahan parent trick kaam nahi karegi
Directed me vis[nb] == true ka matlab cycle nahi hota. Dekho:
Bayein: 0→1, 0→2, 1→2. 2 visited milta hai par cycle nahi. Isliye extra info chahiye.
Solution: do arrays rakho.
vis[] — ye node kabhi bhi visit hua tha?
pathVis[] — ye node abhi wale recursion path pe hai?
Cycle tabhi jab pathVis[nb] == true. Aur DFS se return karte waqt pathVis[node] = false karna zaroori hai — wo node ab is path pe nahi raha.
Java
publicboolean isCyclic(int V, List<List<Integer>> adj) {
boolean[] vis = newboolean[V], pathVis = newboolean[V];
for (int i = 0; i < V; i++)
if (!vis[i] && dfs(i, adj, vis, pathVis)) returntrue;
returnfalse;
}
privateboolean dfs(int node, List<List<Integer>> adj,
boolean[] vis, boolean[] pathVis) {
vis[node] = true;
pathVis[node] = true;
for (int nb : adj.get(node)) {
if (!vis[nb]) {
if (dfs(nb, adj, vis, pathVis)) returntrue;
} elseif (pathVis[nb]) {
returntrue; // back edge = cycle
}
}
pathVis[node] = false; // *** BACKTRACK — ye line hi sab kuch hai ***returnfalse;
}
Wo ek line:pathVis[node] = false hataoge toh pathVis aur vis ek jaise ho jayenge, aur upar wala left-side example galat "cycle" bata dega. Ye single line poore Q17 ka dil hai.
Trace — 0→1, 1→2, 2→0
stepactionpathVisnote
1enter 00vis={0}
2enter 101vis={0,1}
3enter 2012vis={0,1,2}
42 → 00 path pe hai!pathVis[0]=true → CYCLE
Alternative encoding (interview me impress karta hai): ek hi int[] state array — 0 = unvisited, 1 = in progress, 2 = done. state[nb] == 1 mile toh cycle. Ye "white-grey-black" colouring CLRS wali hai.
Problem: Ek node "safe" hai agar usse shuru hone wale har path terminal node (out-degree 0) pe khatam hota hai. Saare safe nodes sorted order me do.
Soch
Reverse framing: node safe nahi hai agar wo kisi cycle ka hissa hai, ya kisi cycle tak pahunch sakta hai. Toh Q17 ka code lo aur ek extra array check[] rakho — jo node cycle me nahi phansa, wo safe.
Java
publicList<Integer> eventualSafeNodes(int[][] graph) {
int n = graph.length;
boolean[] vis = newboolean[n], pathVis = newboolean[n], safe = newboolean[n];
for (int i = 0; i < n; i++)
if (!vis[i]) dfs(i, graph, vis, pathVis, safe);
List<Integer> res = newArrayList<>();
for (int i = 0; i < n; i++) if (safe[i]) res.add(i);
return res; // 0..n-1 loop se already sorted
}
privateboolean dfs(int node, int[][] g, boolean[] vis,
boolean[] pathVis, boolean[] safe) {
vis[node] = true;
pathVis[node] = true;
for (int nb : g[node]) {
if (!vis[nb]) {
if (dfs(nb, g, vis, pathVis, safe)) returntrue; // cycle mila
} elseif (pathVis[nb]) returntrue;
}
pathVis[node] = false;
safe[node] = true; // yahan tak pahunche = koi cycle nahi milareturnfalse;
}
Kahn se bhi hota hai (Q20 ke baad wapas aana): graph ko reverse karo, phir Kahn's chalao. Jo nodes topo order me nikal aayen wo safe hain, jo phase gaye wo cycle me hain. Same answer, alag lens.
Khud try karo
graph = [[1,2],[2,3],[5],[0],[5],[],[]] pe answer [2,4,5,6] kyun hai?
Phase 3
Topological Sort
"Pehle kya, phir kya" — dependency ordering. Sirf DAG pe possible hai (directed + acyclic). Agar cycle hai toh valid order exist hi nahi karta — aur wahi baat cycle detection ka doosra tareeka ban jati hai.
Phase 3 · skeleton
Topological order = nodes ki aisi line jisme har edge u→v ke liye u pehle aaye, v baad me.
DFS wala: node se return hote waqt use stack me daalo. Aakhir me stack ulta karke padho. (Jo sabse baad me khatam hua, wo sabse pehle aayega.)
Kahn wala (BFS): indegree gino. Jinka indegree 0 hai unhe queue me daalo. Ek nikaalo → answer me daalo → uske padosiyon ka indegree ghatao → jiska 0 ho gaya use queue me daalo.
Cycle check free me: Kahn me agar answer ki length < V hai, toh cycle hai. Bas.
Q19
Topo Sort — DFS
GFGstack
Har teer bayein se dayein — yahi topological order ka matlab hai
Java · DFS + stack
publicint[] topoSort(int V, List<List<Integer>> adj) {
boolean[] vis = newboolean[V];
Deque<Integer> st = newArrayDeque<>();
for (int i = 0; i < V; i++) if (!vis[i]) dfs(i, adj, vis, st);
int[] res = newint[V];
int idx = 0;
while (!st.isEmpty()) res[idx++] = st.pop(); // ulta padhoreturn res;
}
privatevoid dfs(int node, List<List<Integer>> adj, boolean[] vis, Deque<Integer> st) {
vis[node] = true;
for (int nb : adj.get(node)) if (!vis[nb]) dfs(nb, adj, vis, st);
st.push(node); // *** RETURN ke waqt push — entry pe nahi ***
}
Wo ek line:st.push(node) loop ke baad hai, pehle nahi. Logic: node tab tak push nahi hoga jab tak uske saare descendants push na ho jayein. Isliye wo unke upar baithta hai → pop pe pehle aata hai.
DFS wala topo sort cycle detect nahi karta. Cycle wale graph pe bhi kuch na kuch return kar dega — galat. Isliye agar "cycle ho sakti hai" toh Kahn use karo, ya pehle Q17 se check kar lo.
Q20
Kahn's Algorithm
BFS topoindegreeworkhorse
Ye Phase 3 ka sabse zyada use hone wala algorithm hai. Q21, Q22, Q23, Q24 sab isi ke upar bane hain.
Idea
Indegree = node me kitne teer aa rahe hain. Jiska indegree 0 hai, uski koi dependency baaki nahi — wo abhi kiya ja sakta hai. Use nikaalo, aur uske padosiyon ka indegree 1 ghata do (unki ek dependency poori ho gayi). Jiska 0 ho gaya, wo ab ready hai.
Java · Kahn (yaad kar lo)
publicint[] topoSort(int V, List<List<Integer>> adj) {
int[] indeg = newint[V];
for (int u = 0; u < V; u++)
for (int v : adj.get(u)) indeg[v]++;
Queue<Integer> q = newLinkedList<>();
for (int i = 0; i < V; i++) if (indeg[i] == 0) q.add(i);
int[] res = newint[V];
int idx = 0;
while (!q.isEmpty()) {
int node = q.poll();
res[idx++] = node;
for (int nb : adj.get(node)) {
if (--indeg[nb] == 0) q.add(nb);
}
}
return res; // agar idx < V hai toh cycle thi (Q21 dekho)
}
Trace — 5→2, 4→2, 2→3, 3→1, 3→0
steppopqueueindegree updates
0—45indeg: [1,1,2,1,0,0]
145indeg[2] 2→1, abhi 0 nahi
252indeg[2] 1→0 → push
323indeg[3] 1→0 → push
4310dono ka indeg 0
51, 0emptyorder: 4 5 2 3 1 0 (6 nodes ✓)
Time
O(V + E)
Space
O(V)
Bonus
cycle detection free
Lexicographic order?
Queue ki jagah PriorityQueue
Khud try karo
Queue ko PriorityQueue bana do — ab lexicographically smallest topo order milega. Kab kaam aata hai? (Jab question "smallest valid order" maange)
Cycle ke andar wale har node ka indegree kabhi 0 nahi ho payega — unki dependency ek doosre pe hai aur wo circle me phansi hai. Toh wo kabhi queue me nahi ghusenge. Result: topo list me sab nodes nahi aayenge.
Java
publicboolean isCyclic(int V, List<List<Integer>> adj) {
int[] indeg = newint[V];
for (int u = 0; u < V; u++) for (int v : adj.get(u)) indeg[v]++;
Queue<Integer> q = newLinkedList<>();
for (int i = 0; i < V; i++) if (indeg[i] == 0) q.add(i);
int count = 0;
while (!q.isEmpty()) {
int node = q.poll();
count++;
for (int nb : adj.get(node)) if (--indeg[nb] == 0) q.add(nb);
}
return count != V; // sab nahi nikle = cycle hai
}
DFS vs Kahn cycle detection: dono O(V+E). DFS kaunsa cycle hai ye bata sakta hai (pathVis se path nikal sakte ho); Kahn sirf haan/naa deta hai, par code saaf aur recursion-free hai. Bade n pe Kahn safe hai.
Q22
Course Schedule I & II
LC 207 · LC 210Kahn direct
Problem I:prerequisites[i] = [a, b] matlab a lene se pehle b lena hai. Saare courses complete kar sakte ho? Problem II: Ek valid order return karo (ya empty array).
Soch
Ye Q20 aur Q21 ka literal rebranding hai. Sirf ek cheez dhyaan se: edge kis taraf jayegi?
[a, b] = "b pehle, a baad me" → edge b → a. Yani adj.get(b).add(a). Ulta likh diya toh answer bhi ulta aayega aur tumhe pata bhi nahi chalega.
Java · Course Schedule II (I bhi isi se nikal aata hai)
publicint[] findOrder(int numCourses, int[][] prerequisites) {
int n = numCourses;
List<List<Integer>> adj = newArrayList<>();
for (int i = 0; i < n; i++) adj.add(newArrayList<>());
int[] indeg = newint[n];
for (int[] p : prerequisites) {
adj.get(p[1]).add(p[0]); // p[1] pehle → p[0]
indeg[p[0]]++;
}
Queue<Integer> q = newLinkedList<>();
for (int i = 0; i < n; i++) if (indeg[i] == 0) q.add(i);
int[] res = newint[n];
int idx = 0;
while (!q.isEmpty()) {
int node = q.poll();
res[idx++] = node;
for (int nb : adj.get(node)) if (--indeg[nb] == 0) q.add(nb);
}
return idx == n ? res : newint[0]; // cycle → empty
}
// Course Schedule I: bas return idx == n;
Edge direction: LC 207/210 me [a, b] ka matlab "a ke liye b chahiye". Toh teer b→a. Alien Dictionary (Q23) me bhi yahi soch lagegi — "kaun pehle" wahi source hai.
Khud try karo
numCourses = 2, prerequisites = [[1,0]] → order [0,1]. Ulta edge daal ke dekho — kya milta hai?
[[1,0],[0,1]] → empty. idx kitna rukega?
Q23
Alien Dictionary
LC 269graph bananaKahn
Problem: Ek alien language ke K letters hain aur uske words sorted order me diye hain. Uski alphabet order batao.
Soch — asli kaam graph banane me hai
Do consecutive words w1 aur w2 lo. Unhe left se compare karo. Pehle jis position pe letters alag hue, wahi ek rule deta hai: w1[i] pehle aata hai, w2[i] baad me → edge w1[i] → w2[i]. Aur usse aage compare karne ka koi matlab nahi — break kar do.
Saare rules se DAG bana, phir Kahn chala do. Bas.
Har consecutive pair se zyada se zyada ek hi edge nikalti hai
Java
publicString findOrder(String[] dict, int N, int K) {
List<List<Integer>> adj = newArrayList<>();
for (int i = 0; i < K; i++) adj.add(newArrayList<>());
int[] indeg = newint[K];
for (int i = 0; i < N - 1; i++) {
String s1 = dict[i], s2 = dict[i + 1];
int len = Math.min(s1.length(), s2.length());
for (int j = 0; j < len; j++) {
if (s1.charAt(j) != s2.charAt(j)) {
int u = s1.charAt(j) - 'a', v = s2.charAt(j) - 'a';
adj.get(u).add(v);
indeg[v]++;
break; // *** pehla farak hi rule deta hai ***
}
}
}
Queue<Integer> q = newLinkedList<>();
for (int i = 0; i < K; i++) if (indeg[i] == 0) q.add(i);
StringBuilder sb = newStringBuilder();
while (!q.isEmpty()) {
int node = q.poll();
sb.append((char)(node + 'a'));
for (int nb : adj.get(node)) if (--indeg[nb] == 0) q.add(nb);
}
return sb.length() == K ? sb.toString() : "";
}
Invalid input ka case (LeetCode version me poocha jata hai): agar s1 longer hai aur s2 uska prefix hai — jaise ["abcd", "abc"] — toh ye sorted ho hi nahi sakta. Us case me turant "" return karo. Loop me koi farak nahi milta isliye ye check alag se lagana padta hai.
Order unique hai ya nahi: agar kisi step pe queue me ek se zyada node hain, toh ek se zyada valid orders exist karte hain. Kuch versions me ye bhi poocha jata hai.
Khud try karo
["baa","abcd","abca","cab","cad"], K=4 → "bdac". Haath se edges nikalo.
Prefix wala invalid case handle karne ki line khud add karo.
Q24
Shortest Path in DAG
GFGtopo + relaxO(V+E)
Problem: Weighted DAG me source 0 se har node ki shortest distance nikalo. Weights negative bhi ho sakte hain.
Soch — Dijkstra se bhi tez
DAG me ek magic property hai: agar tum topological order me nodes process karo, toh jab tum node u pe pahuncho, dist[u] already final ho chuki hoti hai — kyunki u tak pahunchne wale saare nodes pehle process ho chuke hain.
Toh: topo sort nikalo → us order me har node ke edges relax karo. O(V + E). Dijkstra ka log factor bhi nahi lagta, aur negative weights bhi chal jate hain.
Java
publicint[] shortestPath(int V, int E, int[][] edges) {
List<int[]>[] adj = newList[V];
for (int i = 0; i < V; i++) adj[i] = newArrayList<>();
for (int[] e : edges) adj[e[0]].add(newint[]{e[1], e[2]}); // u, v, wt// 1) topo orderboolean[] vis = newboolean[V];
Deque<Integer> st = newArrayDeque<>();
for (int i = 0; i < V; i++) if (!vis[i]) topo(i, adj, vis, st);
// 2) relax in topo orderint[] dist = newint[V];
Arrays.fill(dist, Integer.MAX_VALUE);
dist[0] = 0;
while (!st.isEmpty()) {
int u = st.pop();
if (dist[u] == Integer.MAX_VALUE) continue; // u tak pahunche hi nahifor (int[] nb : adj[u]) {
int v = nb[0], wt = nb[1];
if (dist[u] + wt < dist[v]) dist[v] = dist[u] + wt;
}
}
for (int i = 0; i < V; i++) if (dist[i] == Integer.MAX_VALUE) dist[i] = -1;
return dist;
}
privatevoid topo(int u, List<int[]>[] adj, boolean[] vis, Deque<Integer> st) {
vis[u] = true;
for (int[] nb : adj[u]) if (!vis[nb[0]]) topo(nb[0], adj, vis, st);
st.push(u);
}
Wo continue wali line: agar dist[u] abhi MAX_VALUE hai (u source se reachable hi nahi), aur tum dist[u] + wt karoge → integer overflow → negative number → galat answers. Ye check zaroori hai.
Longest path in DAG: yahi code, bas < ki jagah > aur MAX_VALUE ki jagah MIN_VALUE. Longest path general graph me NP-hard hai, par DAG me trivial — ye ek badhiya interview follow-up hai.
Khud try karo
Isse Dijkstra (Q26) se compare karo — DAG pe kaunsa tez, aur kyun.
Negative weight daal ke dono chala ke dekho. Dijkstra galat kyun ho jata hai?
Phase 4
Shortest Path
Ab weights aa gaye. Poora phase ek hi sawaal ke around hai: "kaunsa algorithm?" — aur wo sawaal graph ki teen properties se decide hota hai: weights hain ya nahi, negative hain ya nahi, aur single-source chahiye ya all-pairs.
Phase 4 · skeleton — decision table
Ye table interview se pehle ek baar dekhna kaafi hai:
Situation
Algorithm
Time
Unweighted (ya sab weights = 1)
BFS
O(V+E)
Weights 0 aur 1 hi hain
0-1 BFS (Deque)
O(V+E)
DAG, koi bhi weight
Topo + relax (Q24)
O(V+E)
Positive weights, single source
Dijkstra
O(E log V)
Negative weights ho sakte hain
Bellman-Ford
O(V×E)
Negative cycle detect karni hai
Bellman-Ford
O(V×E)
All pairs, chhota V (≤ 400)
Floyd-Warshall
O(V³)
Har algorithm ka dil ek hi line hai — RELAXATION: if (dist[u] + wt < dist[v]) dist[v] = dist[u] + wt;
Farak sirf itna hai ki kis order me relax karte ho. BFS: level order. Dijkstra: sabse chhoti dist wala pehle (PQ). Bellman-Ford: sab edges, V-1 baar. Floyd-Warshall: har intermediate node ke through.
Q25
Shortest Path — Unit Weights
GFGplain BFS
Problem: Undirected unweighted graph, source diya hai. Har node ki shortest distance nikalo. Unreachable ko -1.
Soch
Q3 wala BFS hi hai, bas vis[] ki jagah dist[] rakho. dist[nb] == -1 hi "abhi tak visit nahi hua" ka kaam kar deta hai — do arrays ki zaroorat nahi.
Java
publicint[] shortestPath(List<List<Integer>> adj, int V, int src) {
int[] dist = newint[V];
Arrays.fill(dist, -1);
dist[src] = 0;
Queue<Integer> q = newLinkedList<>();
q.add(src);
while (!q.isEmpty()) {
int node = q.poll();
for (int nb : adj.get(node)) {
if (dist[nb] == -1) { // pehli baar pahunche = shortest
dist[nb] = dist[node] + 1;
q.add(nb);
}
}
}
return dist;
}
Kyun "pehli baar = shortest"? BFS layer-by-layer chalta hai. Node v pe pehli baar pahunchna matlab source se uski minimum layer — baad me koi lamba raasta usse chhota ho hi nahi sakta, kyunki har edge ka cost 1 hai. Ye guarantee weighted graph me toot jati hai — isliye Dijkstra chahiye.
Q26
Dijkstra's Algorithm
corePriorityQueuepositive weights
Problem: Weighted graph (saare weights ≥ 0). Source se har node ki shortest distance.
Soch
BFS ki problem: queue "kam edges" wale ko pehle nikaalta hai, "kam weight" wale ko nahi. Fix: Queue ki jagah PriorityQueue lagao, jo hamesha sabse chhoti current distance wale node ko pehle nikaale.
Greedy invariant: jab PQ se koi node pop hota hai, uski distance final ho chuki hoti hai. Kyunki saare weights non-negative hain, ab aage se aane wala koi raasta chhota ho hi nahi sakta.
0→1 direct 4 hai, par 0→2→1 sirf 3. Greedy pop order isko pakad leta hai.
Java · Dijkstra (ye poora yaad karo)
publicint[] dijkstra(int V, List<int[]>[] adj, int src) {
int[] dist = newint[V];
Arrays.fill(dist, Integer.MAX_VALUE);
dist[src] = 0;
// {distance, node} — distance pe sortPriorityQueue<int[]> pq = newPriorityQueue<>((a, b) -> a[0] - b[0]);
pq.add(newint[]{0, src});
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int d = cur[0], u = cur[1];
if (d > dist[u]) continue; // *** stale entry — skip ***for (int[] nb : adj[u]) {
int v = nb[0], wt = nb[1];
if (d + wt < dist[v]) {
dist[v] = d + wt;
pq.add(newint[]{dist[v], v});
}
}
}
return dist;
}
Trace — upar wale graph pe, src = 0
popdPQ (dist,node)relax
——0,0dist=[0,∞,∞,∞]
001,24,1dist[1]=4, dist[2]=1
213,14,19,31+2=3 < 4 → dist[1]=3
134,18,39,33+5=8 < 9 → dist[3]=8
148,39,34 > dist[1]=3 → skip
389,3final
39empty9 > 8 → skip. dist=[0,3,1,8]
Wo if (d > dist[u]) continue; line kyun: hum PQ se purani entries hataate nahi (Java PQ me decrease-key nahi hai), toh ek node ke liye kai entries pad sakti hain. Bina is check ke wo nodes dobara process honge — answer galat nahi hoga par time barbaad hoga. Iske bina bade tests pe TLE mil sakta hai.
Comparator overflow:(a,b) -> a[0] - b[0] tab tootta hai jab distances bahut badi hon (subtraction overflow). Safe version: Comparator.comparingInt(a -> a[0]), ya long use karo.
Time
O(E log V)
Space
O(V + E)
Negative weight?
NAHI — galat answer
Pop = final?
Haan (non-negative weights pe)
Negative weight pe Dijkstra kyun tootta hai: greedy pop maan leta hai ki "ab isse chhota raasta nahi milega". Negative edge us assumption ko tod deta hai — baad me mila lamba raasta bhi negative edge se sasta ho sakta hai. Iska fix Q32 (Bellman-Ford) hai.
Khud try karo
Ek chhota graph banao ek negative edge ke saath, aur Dijkstra haath se chala ke dekho kahan galat hota hai.
Problem: Sirf distance nahi, raasta bhi chahiye — node 1 se node n tak ka shortest path.
Soch
Jab bhi tum dist[v] update karo, saath me likh lo ki kis node se aaye the: parent[v] = u. Aakhir me destination se peeche-peeche chalte jao jab tak source na aa jaye, phir list reverse kar do.
Ye trick har shortest-path algorithm pe lagti hai — BFS, Dijkstra, Bellman-Ford, sab pe.
Java · Dijkstra + parent
publicList<Integer> shortestPath(int n, int m, int[][] edges) {
List<int[]>[] adj = newList[n + 1];
for (int i = 1; i <= n; i++) adj[i] = newArrayList<>();
for (int[] e : edges) {
adj[e[0]].add(newint[]{e[1], e[2]});
adj[e[1]].add(newint[]{e[0], e[2]});
}
int[] dist = newint[n + 1], parent = newint[n + 1];
Arrays.fill(dist, Integer.MAX_VALUE);
for (int i = 1; i <= n; i++) parent[i] = i; // apna hi parent = shuruaat
dist[1] = 0;
PriorityQueue<int[]> pq = newPriorityQueue<>((a, b) -> a[0] - b[0]);
pq.add(newint[]{0, 1});
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int d = cur[0], u = cur[1];
if (d > dist[u]) continue;
for (int[] nb : adj[u]) {
int v = nb[0], wt = nb[1];
if (d + wt < dist[v]) {
dist[v] = d + wt;
parent[v] = u; // *** yahan yaad rakho ***
pq.add(newint[]{dist[v], v});
}
}
}
List<Integer> path = newArrayList<>();
if (dist[n] == Integer.MAX_VALUE) { path.add(-1); return path; }
int node = n;
while (parent[node] != node) { // source pe parent khud hota hai
path.add(node);
node = parent[node];
}
path.add(1);
Collections.reverse(path);
return path;
}
Ye ek chhota pattern hai jo bade sawaalon me kaam aata hai: Word Ladder II, "print all shortest paths", "reconstruct the route" — sab me parent (ya parents ki list) rakhni padti hai. Ek path chahiye toh int[] parent, saare paths chahiye toh List<Integer>[] parents.
Khud try karo
BFS version pe parent array lagao (Q25 wale code pe).
Path unreachable ho toh [-1] return hota hai — wo check kahan lagaya hai, dhoondo.
Q28
Shortest Distance in Binary Maze
LC 1091 · GFGgrid BFS
Problem: Binary grid, 1 = chal sakte ho, 0 = deewar. Source se destination tak minimum steps.
Soch
Saare moves ka cost 1 hai → plain BFS, Dijkstra ki zaroorat nahi. Ye pehchan zaroori hai — log yahan bewajah PQ laga dete hain aur log factor de baithte hain.
Java
publicint shortestPath(int[][] grid, int[] src, int[] dest) {
if (src[0] == dest[0] && src[1] == dest[1]) return0;
int n = grid.length, m = grid[0].length;
int[][] dist = newint[n][m];
for (int[] row : dist) Arrays.fill(row, Integer.MAX_VALUE);
dist[src[0]][src[1]] = 0;
Queue<int[]> q = newLinkedList<>();
q.add(newint[]{src[0], src[1]});
int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
while (!q.isEmpty()) {
int[] cur = q.poll();
int r = cur[0], c = cur[1];
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < n && nc >= 0 && nc < m
&& grid[nr][nc] == 1 && dist[r][c] + 1 < dist[nr][nc]) {
dist[nr][nc] = dist[r][c] + 1;
if (nr == dest[0] && nc == dest[1]) return dist[nr][nc]; // early exit
q.add(newint[]{nr, nc});
}
}
}
return -1;
}
Early exit: BFS me destination pe pehli baar pahunchte hi return kar sakte ho — wahi shortest hai. Dijkstra me bhi kar sakte ho (pop ke waqt). Bade grids pe ye kaafi time bachata hai.
Khud try karo
LC 1091 me 8-directional movement hai — sirf dr/dc badalna hai.
Agar kuch cells ka cost 2 hota (jaise "mud"), toh kaunsa algorithm chahiye hota?
Q29
Path With Minimum Effort
LC 1631Dijkstra variantminimax path
Problem: Heights ka grid. Ek path ka "effort" = us path pe consecutive cells ke beech ka maximum absolute difference. Top-left se bottom-right tak minimum possible effort nikalo.
Soch — cost ka matlab badal gaya
Yahan path ka cost sum nahi hai, max hai. Toh relaxation line badal jayegi:
Baaki poora Dijkstra bilkul same. Ye "minimax path" pattern hai — ek baar dekh lo toh har jagah pehchaan loge.
Java
publicint minimumEffortPath(int[][] heights) {
int n = heights.length, m = heights[0].length;
int[][] eff = newint[n][m];
for (int[] row : eff) Arrays.fill(row, Integer.MAX_VALUE);
eff[0][0] = 0;
// {effort, row, col}PriorityQueue<int[]> pq = newPriorityQueue<>((a, b) -> a[0] - b[0]);
pq.add(newint[]{0, 0, 0});
int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int d = cur[0], r = cur[1], c = cur[2];
if (r == n - 1 && c == m - 1) return d; // pop = final, return kar doif (d > eff[r][c]) continue;
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr < 0 || nr >= n || nc < 0 || nc >= m) continue;
int newEff = Math.max(d, Math.abs(heights[nr][nc] - heights[r][c]));
if (newEff < eff[nr][nc]) {
eff[nr][nc] = newEff;
pq.add(newint[]{newEff, nr, nc});
}
}
}
return0;
}
Ye DSU se bhi hota hai (Q35 ke baad wapas aana): saari edges ko difference ke hisaab se sort karo, ek-ek karke union karte jao, aur jis edge pe (0,0) aur (n-1,m-1) ek component me aa jayein — uska weight hi answer hai. Bilkul Kruskal jaisa. Dono O(E log E) ke aaspaas hain.
Khud try karo
LC 778 (Swim in Rising Water) — Q43 me hai, wahi minimax pattern par cost max(t, grid[nr][nc]).
Agar path ka cost "minimum edge on path" ko maximize karna ho (maximin), toh comparator kaise badlega?
Q30
Cheapest Flights Within K Stops
LC 787state = (node, stops)classic trap
Problem: Flights ka weighted directed graph. src se dst tak sabse sasta ticket, par zyada se zyada k stops allowed.
Soch — yahan Dijkstra ka greedy toot jata hai
Constraint ne problem badal di. Ho sakta hai ek node tak sasta raasta 5 stops le, aur mehnga raasta 2 stops. Sasta wala aage jaake useless ho jaye. Yani "kam cost" ab final nahi hai — cost aur stops dono maayne rakhte hain.
Fix: node ki jagah state (node, stops) ko node maano. Aur PQ ki jagah simple Queue use karo, stops ke hisaab se level-by-level badho. Kyunki har level exactly ek stop hai, BFS naturally stops ko order me rakhta hai.
Java · BFS on (node, stops)
publicint findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
List<int[]>[] adj = newList[n];
for (int i = 0; i < n; i++) adj[i] = newArrayList<>();
for (int[] f : flights) adj[f[0]].add(newint[]{f[1], f[2]});
int[] dist = newint[n];
Arrays.fill(dist, Integer.MAX_VALUE);
dist[src] = 0;
Queue<int[]> q = newLinkedList<>(); // {node, cost}
q.add(newint[]{src, 0});
int stops = 0;
while (!q.isEmpty() && stops <= k) {
int sz = q.size();
for (int i = 0; i < sz; i++) {
int[] cur = q.poll();
int u = cur[0], cost = cur[1];
for (int[] nb : adj[u]) {
int v = nb[0], w = nb[1];
if (cost + w < dist[v]) {
dist[v] = cost + w;
q.add(newint[]{v, cost + w});
}
}
}
stops++;
}
return dist[dst] == Integer.MAX_VALUE ? -1 : dist[dst];
}
Java · Bellman-Ford version (aur bhi saaf)
publicint findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
int[] dist = newint[n];
Arrays.fill(dist, Integer.MAX_VALUE);
dist[src] = 0;
for (int round = 0; round <= k; round++) { // k+1 edges takint[] temp = dist.clone(); // *** clone zaroori hai ***for (int[] f : flights) {
int u = f[0], v = f[1], w = f[2];
if (dist[u] != Integer.MAX_VALUE && dist[u] + w < temp[v]) {
temp[v] = dist[u] + w;
}
}
dist = temp;
}
return dist[dst] == Integer.MAX_VALUE ? -1 : dist[dst];
}
Wo clone() kyun: ek round me har node ko sirf ek aur edge use karne ki permission hai. Agar tum dist ko in-place update karoge, toh ek hi round me chain ban jayegi (u→v→w) aur stops ki ginti galat ho jayegi. temp pichle round ke dist se hi padhta hai — isse "exactly one more edge" enforce hota hai.
Interview line: "k stops matlab zyada se zyada k+1 edges" — ye off-by-one clarify kar lena. 0 stops = direct flight = 1 edge.
Pehla version PQ se likh ke dekho — kahan galat hoga?
Q31
Number of Ways to Arrive at Destination
LC 1976Dijkstra + counting
Problem: 0 se n-1 tak kitne alag shortest paths hain? Answer mod 1e9+7.
Soch — Dijkstra ke saath ek counting array
Dijkstra chalao, saath me ways[] rakho. Jab node v ko relax karo:
Naya chhota raasta mila (d + wt < dist[v]): purane saare raaste bekaar. ways[v] = ways[u].
Utna hi raasta mila (d + wt == dist[v]): ye ek aur tareeka hai. ways[v] += ways[u].
Bas do lines ka farak hai poore Dijkstra me.
Java
publicint countPaths(int n, int[][] roads) {
finalint MOD = 1_000_000_007;
List<long[]>[] adj = newList[n];
for (int i = 0; i < n; i++) adj[i] = newArrayList<>();
for (int[] r : roads) {
adj[r[0]].add(newlong[]{r[1], r[2]});
adj[r[1]].add(newlong[]{r[0], r[2]});
}
long[] dist = newlong[n];
long[] ways = newlong[n];
Arrays.fill(dist, Long.MAX_VALUE);
dist[0] = 0;
ways[0] = 1;
PriorityQueue<long[]> pq = newPriorityQueue<>((a, b) -> Long.compare(a[0], b[0]));
pq.add(newlong[]{0, 0});
while (!pq.isEmpty()) {
long[] cur = pq.poll();
long d = cur[0];
int u = (int) cur[1];
if (d > dist[u]) continue;
for (long[] nb : adj[u]) {
int v = (int) nb[0];
long w = nb[1];
if (d + w < dist[v]) {
dist[v] = d + w;
ways[v] = ways[u]; // reset
pq.add(newlong[]{dist[v], v});
} elseif (d + w == dist[v]) {
ways[v] = (ways[v] + ways[u]) % MOD; // add
}
}
}
return (int) (ways[n - 1] % MOD);
}
Do traps: 1. long use karo — weights 109 tak ja sakte hain aur n bhi bada hai, int me distance overflow ho jayegi. 2. Naye chhote raaste pe ways[v] = ways[u] hai (+= nahi). Purani counting completely invalid ho chuki hai.
Khud try karo
Ek diamond graph banao (0→1→3 aur 0→2→3, dono ka total same) — answer 2 aana chahiye.
Q32
Bellman-Ford
corenegative weightsnegative cycle
Problem: Directed graph jisme negative weights ho sakte hain. Source se shortest distances, aur negative cycle ho toh batao.
Soch
Dijkstra greedy hai isliye negative pe tootta hai. Bellman-Ford brute force hai — isliye nahi tootta.
Idea: shortest path me zyada se zyada V-1 edges ho sakti hain (cycle honi hi nahi chahiye, warna use hata ke chhota banaya ja sakta hai). Toh saari edges ko V-1 baar relax kar do. Har round me kam se kam ek node ki final distance set ho jati hai.
Java
publicint[] bellmanFord(int V, int[][] edges, int src) {
int[] dist = newint[V];
Arrays.fill(dist, (int) 1e8); // MAX_VALUE ki jagah bada sentinel
dist[src] = 0;
// V-1 roundsfor (int i = 0; i < V - 1; i++) {
for (int[] e : edges) {
int u = e[0], v = e[1], w = e[2];
if (dist[u] != (int) 1e8 && dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
}
}
}
// Vth round: agar ab bhi kam ho raha hai → negative cyclefor (int[] e : edges) {
int u = e[0], v = e[1], w = e[2];
if (dist[u] != (int) 1e8 && dist[u] + w < dist[v]) {
returnnewint[]{-1}; // negative cycle
}
}
return dist;
}
Kyun exactly V-1 rounds
roundguaranteedist finalizereason
11-edge pathssrc ke padosisrc se 1 edge door sab final
22-edge paths2 door waleround 1 ke results use hote hain
…………
V-1(V-1)-edgesab finalisse lambi simple path ho hi nahi sakti
Vcheckkam hua?haan → negative cycle hai
Sentinel 1e8 vs Integer.MAX_VALUE: agar tum MAX_VALUE rakhoge aur usme negative weight jodoge, overflow ho jayega. 1e8 bada bhi hai aur addition pe surakshit bhi. Aur dist[u] != 1e8 check phir bhi lagana — unreachable node se relax nahi karna chahiye.
Negative edge vs negative cycle: negative edge theek hai, Bellman-Ford sambhaal leta hai. Negative cycle pe "shortest path" ka koi matlab hi nahi — ghoomte raho, distance ghatta jayega, -∞. Isliye detect karke bahar nikal jate hain.
Time
O(V × E)
Space
O(V)
Graph format
edge list — adj list ki zaroorat nahi
Undirected me?
negative edge = 2-cycle → already negative cycle
Khud try karo
Ek early-exit lagao: agar kisi round me koi update nahi hua, toh break. Kitna faster hota hai?
Negative cycle me phanse hue nodes kaunse hain, wo bhi nikalo. (Hint: Vth round me jo update hue, unse BFS)
Q33
Floyd-Warshall
all pairsDP on graphs3 loops
Problem:Har pair (i, j) ke beech shortest distance.
Soch — ye actually DP hai
Sawaal: "i se j jaane me, kya k ke through jaana sasta hai?"
Ye har k ke liye karo. Sabse important:k ka loop sabse bahar hona chahiye. Kyun? Kyunki k "kaun-kaun se intermediate nodes allowed hain" wali DP dimension hai — pehle sirf node 0 allow, phir 0 aur 1, phir 0,1,2... Loop order galat kiya toh answer galat.
Java
publicvoid shortestDistance(int[][] dist) {
int n = dist.length;
// -1 (no edge) ko bada sentinel banaofor (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
if (dist[i][j] == -1) dist[i][j] = (int) 1e9;
if (i == j) dist[i][j] = 0;
}
for (int k = 0; k < n; k++) // *** k sabse bahar ***for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
// negative cycle: dist[i][i] < 0for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (dist[i][j] == (int) 1e9) dist[i][j] = -1;
}
Loop order:for k, for i, for j. Agar k andar chala gaya toh algorithm hi galat ho jata hai. Ye interview me sabse jaldi pakda jaane wala mistake hai — teen loops dekhkar log order casually likh dete hain.
Negative cycle detection free me: chalane ke baad agar koi dist[i][i] < 0 hai, matlab i se chalke i pe wapas aane me faayda ho raha hai → negative cycle.
Time
O(V³)
Space
O(V²)
Kab
V ≤ 400ish, all-pairs chahiye
Negative weights
chalti hain (cycle nahi)
Dijkstra V baar vs Floyd-Warshall: V baar Dijkstra = O(V × E log V). Sparse graph pe wo behtar hai. Dense graph (E ≈ V²) pe Floyd-Warshall O(V³) jeet jata hai, aur code 5 line ka hai.
Q34
City With Fewest Neighbors at Threshold Distance
LC 1334Floyd-Warshall direct
Problem: Wo city dhoondo jiske distanceThreshold ke andar sabse kam cities hain. Tie ho toh sabse bada index.
Soch
Har city se har city ki distance chahiye → all pairs → Floyd-Warshall. n ≤ 100, toh O(n³) = 106, aaram se.
Java
publicint findTheCity(int n, int[][] edges, int distanceThreshold) {
int[][] dist = newint[n][n];
for (int[] row : dist) Arrays.fill(row, (int) 1e9);
for (int i = 0; i < n; i++) dist[i][i] = 0;
for (int[] e : edges) {
dist[e[0]][e[1]] = e[2];
dist[e[1]][e[0]] = e[2]; // undirected
}
for (int k = 0; k < n; k++)
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
int best = n + 1, ans = -1;
for (int i = 0; i < n; i++) {
int cnt = 0;
for (int j = 0; j < n; j++)
if (i != j && dist[i][j] <= distanceThreshold) cnt++;
if (cnt <= best) { // <= isliye ki tie pe bada index jeete
best = cnt;
ans = i;
}
}
return ans;
}
Tie-breaking:cnt <= best likho, < nahi. Loop 0 se n-1 ja raha hai, toh <= automatically bade index ko jeeta deta hai. Ye ek line poore solution ko pass/fail karti hai.
Khud try karo
Ye same sawaal n baar Dijkstra se karo. n=100 pe kaunsa tez lagega?
Phase 5
DSU & MST
Ab tak tum graph ko ghoom rahe the. Ab tum use jod rahe ho. DSU (Disjoint Set Union) ek chhota sa data structure hai jo "kya ye do nodes ek group me hain?" ka jawaab lagbhag O(1) me deta hai — aur wahi poore phase ka engine hai.
Phase 5 · skeleton
DSU do hi kaam karta hai:find(x) — x ke group ka boss (ultimate parent) kaun hai. union(x, y) — do groups ko mila do.
Kab DSU sochna hai: jab problem "dynamic connectivity" ki ho — edges ek-ek karke aa rahi hain, ya baar-baar "ye do juday hain?" poochna ho. DFS/BFS har query pe poora graph ghoomta hai; DSU nahi.
MST ka matlab: saare nodes ko jodne wala sabse sasta edge-set (V-1 edges, no cycle). Do algorithms — Kruskal (edges sort + DSU) aur Prim (PQ se grow karo).
Q35
Disjoint Set Union
core DSpath compressionunion by size
Soch
Har group ek ulta tree hai. Har node apne parent ko point karta hai; root apne aap ko. Do nodes ek group me hain ⇔ unka root same hai.
Path compression — find karte waqt raaste ke sab nodes ko root se seedha jod do
Do optimizations — dono lagane par har operation lagbhag O(1)
Path compression:find ke dauran raaste ke har node ka parent seedha root bana do.
Union by size (ya rank): chhote tree ko bade tree ke neeche jodo, ulta nahi. Warna tree lambi chain ban jayegi.
Java · DSU class (ye copy-paste template ban jayega)
classDSU {
int[] parent, size;
int components;
DSU(int n) {
parent = newint[n];
size = newint[n];
components = n;
for (int i = 0; i < n; i++) { parent[i] = i; size[i] = 1; }
}
int find(int x) {
if (parent[x] == x) return x;
return parent[x] = find(parent[x]); // *** path compression ***
}
boolean union(int a, int b) {
int ra = find(a), rb = find(b);
if (ra == rb) returnfalse; // already same groupif (size[ra] < size[rb]) { int t = ra; ra = rb; rb = t; }
parent[rb] = ra; // chhota bade ke neeche
size[ra] += size[rb];
components--;
returntrue;
}
boolean connected(int a, int b) { return find(a) == find(b); }
}
union ka boolean return bahut kaam ka hai:true matlab "asli merge hua", false matlab "already juday the". Kruskal me yahi cycle detection hai, Q38 me yahi extra-edges ki ginti hai. Isliye void mat likhna.
find / union
O(α(n)) ≈ O(1)
Space
O(n)
Union by rank vs size
dono chalte hain; size zyada intuitive
Components count
field me maintain karo, muft me
Path compression mat bhoolo. Bina uske ek chain me find O(n) ho jata hai. Aur parent[x] = find(parent[x]) me assignment zaroori hai — sirf return find(parent[x]) likhne se compression hoti hi nahi.
Khud try karo
Union by size hata ke chalao aur ek chain (0-1, 1-2, 2-3, ...) banao — depth kitni ho jayegi?
Ek rollback wala DSU (undo support) kaise banate hain? (Hint: path compression hata do, changes stack me rakho)
Q36
Kruskal's MST
MSTDSUgreedy
Problem: Connected weighted undirected graph. Minimum spanning tree ka total weight nikalo.
Soch — sabse sasta edge pehle
Saari edges ko weight ke hisaab se sort karo. Ek-ek karke uthao:
Agar edge ke dono ends already ek component me hain → skip (cycle ban jayegi)
Warna le lo, union kar do, weight jod do
Jab V-1 edges le li, MST poora. Ye greedy provably optimal hai (cut property).
Java
publicint spanningTree(int V, int[][] edges) { // edges: {u, v, wt}Arrays.sort(edges, (a, b) -> a[2] - b[2]);
DSU dsu = newDSU(V);
int total = 0, taken = 0;
for (int[] e : edges) {
if (dsu.union(e[0], e[1])) { // true = cycle nahi bani
total += e[2];
taken++;
if (taken == V - 1) break; // MST poora
}
}
return total;
}
Trace — edges (0-1,2) (1-2,3) (0-2,1) (2-3,4)
edgewtunion?total / components
0-21liyatotal=1, comp=3
0-12liyatotal=3, comp=2
1-23skip1 aur 2 already juday — cycle
2-34liyatotal=7, taken=3=V-1 → break
Time
O(E log E) — sort dominate
Space
O(V)
Kab Kruskal
sparse graph, edge list di ho
Disconnected?
MST exist nahi karta → minimum spanning forest milega
Maximum spanning tree chahiye? Bas comparator ulta kar do: (a,b) -> b[2] - a[2]. Poora code same.
Q37
Prim's MST
MSTPriorityQueue
Soch — Dijkstra jaisa, par ek line ka farak
Ek node se shuru karo. PQ me uski saari edges daalo. Sabse sasti edge nikaalo — agar uska doosra end abhi tak MST me nahi hai, use MST me le lo aur uski saari edges PQ me daal do.
Dijkstra vs Prim, wo ek line:
Dijkstra PQ me daalta hai dist[u] + wt (source se total distance).
Prim PQ me daalta hai sirf wt (MST se ek edge ki cost).
Bas. Baaki structure bilkul same.
Java
publicint spanningTree(int V, List<int[]>[] adj) {
boolean[] inMST = newboolean[V];
PriorityQueue<int[]> pq = newPriorityQueue<>((a, b) -> a[0] - b[0]); // {wt, node}
pq.add(newint[]{0, 0});
int total = 0;
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int wt = cur[0], u = cur[1];
if (inMST[u]) continue; // *** pop ke waqt check, push pe nahi ***
inMST[u] = true;
total += wt;
for (int[] nb : adj[u]) {
if (!inMST[nb[0]]) pq.add(newint[]{nb[1], nb[0]});
}
}
return total;
}
Yahan inMST check pop pe hona chahiye, push pe nahi — BFS ke ulta. Kyunki ek node ke liye PQ me kai entries (alag-alag weights) padi hoti hain, aur hume sabse sasti wali chahiye. Push ke waqt mark kar doge toh mehngi wali entry pehle lock ho sakti hai.
Kruskal
Prim
Structure
DSU + sorted edges
PriorityQueue
Time
O(E log E)
O(E log V)
Input suits
edge list
adjacency list
Behtar kab
sparse graph
dense graph
MST edges chahiye
seedha mil jate hain
parent array rakho
Khud try karo
MST ki actual edges bhi return karo (dono algorithms me).
Prim me pop wale check ko push pe le jao aur ek aisa graph banao jahan answer galat aaye.
Q38
Make Network Connected
LC 1319DSU counting
Problem: n computers, kuch cables se juday hain. Ek cable hata ke kahin aur laga sakte ho. Minimum kitne moves me sab connected honge? Possible na ho toh -1.
Soch — do numbers hi kaafi hain
Extra edges = jitni edges ne cycle banai (yani union ne false return kiya). Ye "spare cables" hain.
Agar extra >= components - 1 → answer components - 1. Warna -1.
Aur asal me toh sirf ek check kaafi hai: connections.length < n - 1 → -1. Kyunki n nodes ko jodne ke liye kam se kam n-1 edges chahiye hi.
Java
publicint makeConnected(int n, int[][] connections) {
if (connections.length < n - 1) return -1; // cables hi kam hainDSU dsu = newDSU(n);
for (int[] c : connections) dsu.union(c[0], c[1]);
return dsu.components - 1;
}
Ek line ka solution. Jo cheez Q5 (Provinces) me DFS se ginte the, wo DSU me field hai. Yahi DSU ki khoobsurti hai — connectivity ke sawaal ek subtraction ban jate hain.
Q39
Accounts Merge
LC 721DSU on stringsinterview favourite
Problem: Accounts ki list — har account me ek naam aur kuch emails. Do accounts same insaan ke hain agar unme koi ek common email ho. Merge karke sorted emails ke saath return karo.
Soch — email ko "node" mat banao, uska index banao
DSU integers pe kaam karta hai. Toh mapping banao: emailToIndex: email → account index.
Har account ke har email pe: agar email pehli baar dikha, use is account ka index de do. Agar pehle dikha tha → union(currentAccount, jahaanPehleDikhaTha).
Ab har email ko uske account ke find() root ke group me daal do.
Har group ke emails sort karo, aage naam laga do.
Java
publicList<List<String>> accountsMerge(List<List<String>> accounts) {
int n = accounts.size();
DSU dsu = newDSU(n);
Map<String, Integer> emailToIdx = newHashMap<>();
// STEP 1: same email = same insaan → unionfor (int i = 0; i < n; i++) {
for (int j = 1; j < accounts.get(i).size(); j++) { // j=0 naam haiString email = accounts.get(i).get(j);
if (emailToIdx.containsKey(email)) {
dsu.union(i, emailToIdx.get(email));
} else {
emailToIdx.put(email, i);
}
}
}
// STEP 2: har root ke neeche emails collect karoMap<Integer, List<String>> groups = newHashMap<>();
for (Map.Entry<String, Integer> en : emailToIdx.entrySet()) {
int root = dsu.find(en.getValue());
groups.computeIfAbsent(root, x -> newArrayList<>()).add(en.getKey());
}
// STEP 3: sort + naam lagaoList<List<String>> res = newArrayList<>();
for (Map.Entry<Integer, List<String>> en : groups.entrySet()) {
List<String> emails = en.getValue();
Collections.sort(emails);
List<String> row = newArrayList<>();
row.add(accounts.get(en.getKey()).get(0)); // naam
row.addAll(emails);
res.add(row);
}
return res;
}
Naam se merge mat karna. Do alag "John Smith" ho sakte hain. Merge ka criteria sirf common email hai. Ye question ka main trap hai.
Ye pattern jahan-jahan aata hai: "same phone number ya same email wale merchant records ko group karo", "duplicate user profiles milao", "same device fingerprint wale sessions" — sab yahi hai. Node = record index, edge = shared identity field.
Khud try karo
Agar merge criteria "same email ya same phone" ho toh code me kya badlega? (Hint: do maps)
DFS/BFS se bhi ho sakta hai — graph banao email↔account ka bipartite. Try karo, aur dekho DSU kitna saaf hai.
Q40
Number of Islands II
LC 305online queriesDSU zaroori
Problem: Shuru me poora grid paani hai. Ek-ek karke cells ko land banate jao. Har operation ke baad current island count batao.
Soch — yahi wo problem hai jahan DFS haar jata hai
Har query pe poora grid DFS karoge → O(k × n × m). DSU se O(k × α).
Algorithm: naya land cell aaya → count++. Ab uske 4 padosiyon me se jo bhi already land hai, us se union karo — har successful union pecount-- (do islands mil ke ek ban gaye).
2 + 1 - 2 = 1. Ek naya cell do islands ko merge kar sakta hai.
Java
publicList<Integer> numIslands2(int n, int m, int[][] operators) {
DSU dsu = newDSU(n * m);
boolean[][] land = newboolean[n][m];
List<Integer> res = newArrayList<>();
int count = 0;
int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
for (int[] op : operators) {
int r = op[0], c = op[1];
if (land[r][c]) { res.add(count); continue; } // duplicate op
land[r][c] = true;
count++;
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < n && nc >= 0 && nc < m && land[nr][nc]) {
if (dsu.union(r * m + c, nr * m + nc)) count--;
}
}
res.add(count);
}
return res;
}
2D → 1D flattening: cell (r, c) ka DSU index r * m + c hai (m = columns). Ye conversion Q41, Q42 me bhi lagegi — achhe se yaad kar lo. Ulta: r = idx / m, c = idx % m.
Duplicate operation ka case: agar wahi cell dobara land banaya jaye, count nahi badhna chahiye. Ye hidden test case me aksar hota hai.
Q41
Making a Large Island
LC 827DSU + sizes
Problem: Binary grid. Zyada se zyada ek0 ko 1 bana sakte ho. Sabse bada possible island ka size?
Soch — do pass
Pass 1: saare existing islands ko DSU se jod do. Ab har root ke paas uske island ka size hai.
Pass 2: har 0 cell pe khade ho jao. Uske 4 padosiyon ke distinct roots nikalo (Set me daalo — do padosi same island ke ho sakte hain). Un sabke sizes jodo, +1 karo (khud ye cell). Maximum track karo.
Java
publicint largestIsland(int[][] grid) {
int n = grid.length;
DSU dsu = newDSU(n * n);
int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
// PASS 1: existing islands jodofor (int r = 0; r < n; r++)
for (int c = 0; c < n; c++) {
if (grid[r][c] == 0) continue;
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < n && nc >= 0 && nc < n && grid[nr][nc] == 1)
dsu.union(r * n + c, nr * n + nc);
}
}
// PASS 2: har 0 ko flip karke dekhoint best = 0;
for (int r = 0; r < n; r++)
for (int c = 0; c < n; c++) {
if (grid[r][c] == 1) continue;
Set<Integer> roots = newHashSet<>();
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < n && nc >= 0 && nc < n && grid[nr][nc] == 1)
roots.add(dsu.find(nr * n + nc)); // *** distinct roots ***
}
int total = 1;
for (int root : roots) total += dsu.size[root];
best = Math.max(best, total);
}
// edge case: poora grid already 1 hai, koi 0 mila hi nahifor (int i = 0; i < n * n; i++) best = Math.max(best, dsu.size[dsu.find(i)]);
return best;
}
Set kyun zaroori hai: ek 0 cell ke do padosi ek hi island ke ho sakte hain (jaise U-shape ke andar). Bina Set ke us island ka size do baar jud jayega. Ye classic wrong-answer hai.
Aakhri loop kyun: agar grid me ek bhi 0 nahi hai, toh Pass 2 kabhi chalega hi nahi aur best 0 reh jayega. Answer n×n hona chahiye.
Q42
Most Stones Removed
LC 947row/col as nodesclever trick
Problem: Grid pe stones hain. Ek stone hata sakte ho agar uske row ya column me koi aur stone ho. Maximum kitne hata sakte ho?
Soch — do steps ki insight
Insight 1: ek connected group me se sab hata sakte ho siwaay ek ke. (Ek-ek karke hatate jao, aakhri wala akela bach jata hai.) Toh answer = totalStones - components.
Insight 2 (asli trick): stones ko aapas me jodne ke liye har pair check karna O(n²) hai. Iske bajaye rows aur columns ko hi nodes bana do. Ek stone (r, c) ka matlab hai "row r aur column c juday hue hain" → union(r, c).
Collision se bachne ke liye columns ko offset do: column c ka node number c + 10001.
Java
publicint removeStones(int[][] stones) {
DSU dsu = newDSU(20002); // rows 0..10000, cols 10001..20001Set<Integer> used = newHashSet<>();
for (int[] s : stones) {
int rowNode = s[0];
int colNode = s[1] + 10001;
dsu.union(rowNode, colNode);
used.add(rowNode);
used.add(colNode);
}
Set<Integer> roots = newHashSet<>();
for (int node : used) roots.add(dsu.find(node));
return stones.length - roots.size();
}
"Row/col ko node banana" ek reusable trick hai. Jab bhi "same row ya same column me hone se cheezein juday hain" wala sawaal aaye — ye pehli soch honi chahiye. Isse O(n²) pairwise comparison O(n) ban jata hai.
Khud try karo
Offset 10001 kyun, 10000 kyun nahi? (Hint: coordinates 0 se 10000 tak inclusive hain)
Naive O(n²) version bhi likho aur dono ka time compare karo n=1000 pe.
Q43
Swim in Rising Water
LC 778minimaxDijkstra ya DSU
Problem: Grid me har cell ki elevation hai. Time t pe tum us cell pe ja sakte ho jiski elevation ≤ t ho. (0,0) se (n-1,n-1) tak pahunchne ka minimum time?
Soch — Q29 ka bhai
Path ka cost = us path ke cells ka maximum elevation. Minimize karna hai. Wahi minimax pattern.
Java · Dijkstra style
publicint swimInWater(int[][] grid) {
int n = grid.length;
int[][] best = newint[n][n];
for (int[] row : best) Arrays.fill(row, Integer.MAX_VALUE);
best[0][0] = grid[0][0];
PriorityQueue<int[]> pq = newPriorityQueue<>((a, b) -> a[0] - b[0]);
pq.add(newint[]{grid[0][0], 0, 0});
int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int t = cur[0], r = cur[1], c = cur[2];
if (r == n - 1 && c == n - 1) return t;
if (t > best[r][c]) continue;
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr < 0 || nr >= n || nc < 0 || nc >= n) continue;
int nt = Math.max(t, grid[nr][nc]); // *** max, sum nahi ***if (nt < best[nr][nc]) {
best[nr][nc] = nt;
pq.add(newint[]{nt, nr, nc});
}
}
}
return -1;
}
Java · DSU style (elevation order me cells "kholo")
publicint swimInWater(int[][] grid) {
int n = grid.length;
int[] pos = newint[n * n]; // elevation -> cell indexfor (int r = 0; r < n; r++)
for (int c = 0; c < n; c++) pos[grid[r][c]] = r * n + c;
DSU dsu = newDSU(n * n);
boolean[] open = newboolean[n * n];
int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};
for (int t = 0; t < n * n; t++) {
int idx = pos[t], r = idx / n, c = idx % n;
open[idx] = true;
for (int k = 0; k < 4; k++) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < n && nc >= 0 && nc < n && open[nr * n + nc])
dsu.union(idx, nr * n + nc);
}
if (dsu.connected(0, n * n - 1)) return t;
}
return -1;
}
Ye do solutions dekhkar ek baat pakdo: "minimize the maximum" wale sawaal me hamesha teen raaste hote hain — Dijkstra-with-max, DSU-in-sorted-order, ya binary search on answer + BFS feasibility check. Teeno seekhne layak hain; interview me koi bhi chalega.
Phase 6
Advanced — Bridges, Articulation Points, SCC
Ye char sawaal alag lagte hain, par ek hi idea ke roop hain: DFS ke dauran har node pe do numbers rakho — "main kab discover hua" aur "main apne subtree se peeche kitna upar chadh sakta hoon". Un do numbers ki tulna se poora structure khul jata hai.
Phase 6 · skeleton
tin[u] = discovery time — DFS ne u ko kis timer value pe pehli baar dekha. Kabhi nahi badalta.
low[u] = u ke subtree se (parent edge use kiye bina) sabse chhoti tin jahan tak pahunch sakte ho. Ye badalta rehta hai.
Bridge: edge u—v (v child) bridge hai agar low[v] > tin[u]. Yani v ke subtree ka koi bhi raasta u ya usse upar nahi pahunchta — ye edge kaat do toh subtree kat jayega.
Articulation point:low[v] >= tin[u] (non-root ke liye). Root special — do ya zyada children ho toh AP.
Farak sirf > aur >= ka hai. Yahi poora phase hai.
Q44
Bridges in Graph
LC 1192Tarjantin / low
Problem: Wo edges dhoondo jinhe hataane se graph ke components badh jayein. (Critical connections in a network.)
Cycle ki har edge ka backup raasta hota hai — isliye wo bridge nahi
Soch
DFS chalao aur timer badhate jao. Har node ko tin do. Wapas lautte waqt parent ka low update karo: low[u] = min(low[u], low[v]).
Agar padosi v already visited hai (aur parent nahi hai), toh wo back edge hai — upar chadhne ka raasta. Tab low[u] = min(low[u], tin[v]). Yahan tin[v] lena hai, low[v] nahi — back edge se sirf ek hi chhalaang lagti hai.
Java
privateint timer = 0;
publicList<List<Integer>> criticalConnections(int n, List<List<Integer>> connections) {
List<List<Integer>> adj = newArrayList<>();
for (int i = 0; i < n; i++) adj.add(newArrayList<>());
for (List<Integer> e : connections) {
adj.get(e.get(0)).add(e.get(1));
adj.get(e.get(1)).add(e.get(0));
}
int[] tin = newint[n], low = newint[n];
boolean[] vis = newboolean[n];
List<List<Integer>> bridges = newArrayList<>();
dfs(0, -1, adj, vis, tin, low, bridges);
return bridges;
}
privatevoid dfs(int u, int parent, List<List<Integer>> adj, boolean[] vis,
int[] tin, int[] low, List<List<Integer>> bridges) {
vis[u] = true;
tin[u] = low[u] = timer++;
for (int v : adj.get(u)) {
if (v == parent) continue;
if (!vis[v]) {
dfs(v, u, adj, vis, tin, low, bridges);
low[u] = Math.min(low[u], low[v]); // child seif (low[v] > tin[u]) { // *** BRIDGE ***
bridges.add(Arrays.asList(u, v));
}
} else {
low[u] = Math.min(low[u], tin[v]); // back edge — tin, low nahi
}
}
}
Trace — 0-1, 1-2, 2-0, 1-3
nodetinlow (final)check
000root
1102 ke through 0 tak pahunch gaya
220back edge 2→0, tin[0]=0
333koi back edge nahi
1—3checklow[3]=3 > tin[1]=1BRIDGE
0—1checklow[1]=0 > tin[0]=0? nahicycle me hai, bridge nahi
Back edge pe tin[v] lo, low[v] nahi. Bridges ke liye dono se aksar same answer aa jata hai, par articulation points aur SCC me low[v] lena galat results deta hai. Habit sahi banao.
Parallel edges: agar u—v do baar hai toh wo bridge nahi ho sakti, par v == parent wala skip pehli edge pe hi lag jayega. Fix: parent node ki jagah parent edge id track karo.
Q45
Articulation Points
GFGcut vertices
Problem: Wo nodes dhoondo jinhe (aur unki saari edges ko) hataane se graph ke components badh jayein.
Q44 se teen farak
Condition low[v] > tin[u] ki jagah low[v] >= tin[u] ho jati hai. (Bridge me v ka subtree u tak bhi nahi pahunchna chahiye; AP me u tak pahunchna chal jata hai — u hatate hi wo tut jayega.)
Root ka special case: root AP hai agar uske DFS tree me 2 ya zyada children hain.
Answer nodes ka hai, isliye Set/boolean[] me store karo — ek node kai baar mark ho sakta hai.
Java
privateint timer = 0;
publicList<Integer> articulationPoints(int V, List<List<Integer>> adj) {
int[] tin = newint[V], low = newint[V];
boolean[] vis = newboolean[V], isAP = newboolean[V];
for (int i = 0; i < V; i++)
if (!vis[i]) dfs(i, -1, adj, vis, tin, low, isAP);
List<Integer> res = newArrayList<>();
for (int i = 0; i < V; i++) if (isAP[i]) res.add(i);
return res.isEmpty() ? Arrays.asList(-1) : res;
}
privatevoid dfs(int u, int parent, List<List<Integer>> adj, boolean[] vis,
int[] tin, int[] low, boolean[] isAP) {
vis[u] = true;
tin[u] = low[u] = timer++;
int children = 0;
for (int v : adj.get(u)) {
if (v == parent) continue;
if (!vis[v]) {
dfs(v, u, adj, vis, tin, low, isAP);
low[u] = Math.min(low[u], low[v]);
if (low[v] >= tin[u] && parent != -1) isAP[u] = true; // non-root
children++;
} else {
low[u] = Math.min(low[u], tin[v]);
}
}
if (parent == -1 && children > 1) isAP[u] = true; // root rule
}
Root ka rule intuition: agar root ka sirf ek child hai, root hataane se wo child ka subtree ab bhi ek hi tukda rahega. Do children hain toh unke beech ka ek matra connection root hi tha → hataate hi do tukde.
Khud try karo
Ek straight line graph (0-1-2-3-4) me AP kaun-kaun hain? (1, 2, 3 — ends nahi)
Ek triangle me? (koi nahi)
Bridge ke dono endpoints hamesha AP hote hain kya? (Nahi — agar endpoint leaf ho toh nahi)
Q46
Kosaraju's Algorithm — SCC
directed2 DFStranspose
SCC (Strongly Connected Component) = directed graph ka aisa group jisme har node se har doosre node tak raasta ho (dono taraf). Problem: saare SCCs nikalo.
Soch — teen steps, aur ek chalaaki
DFS chalao, finish time ke hisaab se stack me daalo (bilkul Q19 topo sort jaisa).
Graph ko reverse karo — har edge u→v ko v→u bana do.
Stack ke order me reversed graph pe DFS chalao. Har DFS jitne nodes cover karega, wo ek SCC hai.
Kyun kaam karta hai: reverse karne se SCC ke andar ka connectivity nahi badalta (dono taraf raasta tha, ab bhi hai). Par SCCs ke beech ki edges ulti ho jati hain — toh ek SCC se doosre me leak nahi ho sakte. Aur stack order guarantee karta hai ki hum "sabse aakhri" SCC se shuru karein.
Java
publicint kosaraju(int V, List<List<Integer>> adj) {
// STEP 1: finish orderboolean[] vis = newboolean[V];
Deque<Integer> st = newArrayDeque<>();
for (int i = 0; i < V; i++) if (!vis[i]) dfs1(i, adj, vis, st);
// STEP 2: transposeList<List<Integer>> rev = newArrayList<>();
for (int i = 0; i < V; i++) rev.add(newArrayList<>());
for (int u = 0; u < V; u++)
for (int v : adj.get(u)) rev.get(v).add(u);
// STEP 3: stack order me DFS on reversedArrays.fill(vis, false);
int scc = 0;
while (!st.isEmpty()) {
int node = st.pop();
if (!vis[node]) { scc++; dfs2(node, rev, vis); }
}
return scc;
}
privatevoid dfs1(int u, List<List<Integer>> adj, boolean[] vis, Deque<Integer> st) {
vis[u] = true;
for (int v : adj.get(u)) if (!vis[v]) dfs1(v, adj, vis, st);
st.push(u); // return ke waqt
}
privatevoid dfs2(int u, List<List<Integer>> rev, boolean[] vis) {
vis[u] = true;
for (int v : rev.get(u)) if (!vis[v]) dfs2(v, rev, vis);
}
SCCs ko collapse karo toh hamesha DAG banta hai (condensation graph). Isliye kai hard problems ka solution hai: "SCC nikalo → collapse karo → ab DAG pe topo sort ya DP chala do". Ye framing yaad rakhne layak hai.
Time
O(V + E)
Space
O(V + E) — reverse graph
Undirected me?
Matlab hi nahi — wahan SCC = connected component
SCC members chahiye?
dfs2 me list collect karo
Q47
Tarjan's SCC
single DFStin / low again
Kosaraju do DFS aur ek transpose leta hai. Tarjan ek hi DFS me kaam khatam kar deta hai — wahi tin/low machinery jo Q44 me thi, plus ek stack.
Idea
DFS ke dauran nodes ko ek stack pe rakho. Jab kisi node u ke liye low[u] == tin[u] nikle, matlab u apne SCC ka root hai — stack se u tak sab nikaal lo, wahi ek SCC hai.
Ek naya check chahiye: back edge pe low update tabhi karo jab wo node abhi bhi stack pe ho. Agar wo already kisi doosre SCC me ja chuka hai, toh usse hamara koi lena-dena nahi.
Java
privateint timer = 0;
privateint[] tin, low;
privateboolean[] onStack;
privateDeque<Integer> st;
privateList<List<Integer>> sccs;
publicList<List<Integer>> tarjan(int V, List<List<Integer>> adj) {
tin = newint[V]; low = newint[V];
Arrays.fill(tin, -1);
onStack = newboolean[V];
st = newArrayDeque<>();
sccs = newArrayList<>();
for (int i = 0; i < V; i++) if (tin[i] == -1) dfs(i, adj);
return sccs;
}
privatevoid dfs(int u, List<List<Integer>> adj) {
tin[u] = low[u] = timer++;
st.push(u);
onStack[u] = true;
for (int v : adj.get(u)) {
if (tin[v] == -1) { // abhi tak visit nahi
dfs(v, adj);
low[u] = Math.min(low[u], low[v]);
} elseif (onStack[v]) { // *** stack pe hai tabhi ***
low[u] = Math.min(low[u], tin[v]);
}
}
if (low[u] == tin[u]) { // SCC rootList<Integer> comp = newArrayList<>();
while (true) {
int w = st.pop();
onStack[w] = false;
comp.add(w);
if (w == u) break;
}
sccs.add(comp);
}
}
Kosaraju
Tarjan
DFS passes
2
1
Reverse graph
chahiye
nahi chahiye
Time
O(V+E)
O(V+E)
Yaad karna
aasan
mushkil
Interview me
Kosaraju bolo
Tarjan bonus ke liye
Practical advice: interview me Kosaraju likhna kaafi hai — explain karna aasan hai aur same complexity hai. Tarjan tab mention karo jab wo poochein "single pass me ho sakta hai kya?" Aur onStack wali line hi Tarjan ka poora raaz hai — usse hata do toh algorithm silently galat ho jata hai.
Σ
Master cheatsheet
Interview se ek raat pehle sirf ye padhna kaafi hai.
1 · Sawaal padhte hi kaunsa algorithm — decision tree
Sawaal me ye dikhe
Ye socho
Q
"kitne groups / islands / provinces"
DFS/BFS components, ya DSU
5, 6, 38
"minimum steps / seconds / moves" (unweighted)
BFS
8, 13, 25, 28
"minimum cost / distance" (weighted, positive)
Dijkstra
26, 29
negative weights
Bellman-Ford
32
"har pair ke beech distance"
Floyd-Warshall
33, 34
DAG + shortest/longest path
topo sort + relax
24
"kya order me kar sakte hain" / prerequisites
topo sort (Kahn)
20, 22, 23
"kya cycle hai"
undirected: parent · directed: pathVis ya Kahn
14, 17, 21
"do groups me baanto"
bipartite check
16
"sab jodne ki minimum cost"
MST — Kruskal ya Prim
36, 37
edges ek-ek karke aa rahi hain / baar-baar "connected?"
DSU
35, 40
"minimize the maximum" on a path
Dijkstra-with-max, ya DSU sorted, ya binary search
visited push ke waqt mark nahi kiya (BFS); Dijkstra me stale-entry skip nahi
Count 1 zyada / kam
count++ traversal ke andar hai (driver loop me hona chahiye); level counter ka off-by-one
Disconnected graph pe galat
driver loop hi nahi hai — for i in 0..V-1 if(!vis[i])
Directed cycle detect nahi hui
pathVis[node] = false backtrack line missing
DFS true return nahi kar raha
if (dfs(...)) return true; ki jagah sirf dfs(...) likha
Overflow / bakwaas negative distances
MAX_VALUE + wt; sentinel 1e9 use karo aur unreachable pe skip
Floyd-Warshall galat
k ka loop bahar nahi hai
Prim ka MST mehnga aa raha
inMST check push pe kar diya, pop pe hona chahiye
DSU slow
path compression me assignment nahi (parent[x] = find(...))
Grid solution index error
boundary check <n vs <=n; rows/cols ulat gaye
Course Schedule ulta answer
edge direction — [a,b] ka matlab b→a
4 · Do template jo ratt lene chahiye
Template A · component counting (Q5, 6, 12, 38 sab isi pe)
int count = 0;
for (int i = 0; i < n; i++) {
if (!vis[i] && relevant(i)) {
count++;
flood(i); // BFS ya DFS — poora component mark kar de
}
}
Template B · Dijkstra (Q26, 27, 29, 31, 43 sab isi pe)
dist[src] = 0;
pq.add(newint[]{0, src});
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int d = cur[0], u = cur[1];
if (d > dist[u]) continue;
for (int[] nb : adj[u]) {
int v = nb[0], wt = nb[1];
int nd = COMBINE(d, wt); // sum → normal | max → minimaxif (nd < dist[v]) {
dist[v] = nd;
pq.add(newint[]{nd, v});
}
}
}
COMBINE hi wo knob hai. d + wt = classic Dijkstra. Math.max(d, wt) = Q29/Q43 minimax. Ek line badalne se poora naya sawaal ban jata hai.
5 · Padhne ka order
Agar time kam hai aur interview kal hai: Q3, Q4, Q6, Q8, Q17, Q20, Q22, Q26, Q35, Q36. Ye das poore syllabus ka 70% cover kar dete hain. Baaki sab in dus ke variations hain.