Roadmap · 47 questions · Java · Hinglish

Graphs.
Scratch se advanced tak.

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.

unvisited frontier / queue me visited cycle / cut / conflict weight
Graphs
All 47 questions
0 · Neev — Basics
01Graph ki vocabulary 02Representation: matrix vs list 03BFS — level by level 04DFS — gehrai me
1 · Grid & Components
05Number of Provinces 06Number of Islands 07Flood Fill 08Rotten Oranges 090/1 Matrix 10Surrounded Regions 11Number of Enclaves 12Number of Distinct Islands 13Word Ladder I
2 · Cycle & Bipartite
14Cycle in Undirected — BFS 15Cycle in Undirected — DFS 16Bipartite Graph 17Cycle in Directed — DFS 18Eventual Safe States
3 · Topological Sort
19Topo Sort — DFS 20Kahn's Algorithm 21Cycle in Directed — Kahn 22Course Schedule I & II 23Alien Dictionary 24Shortest Path in DAG
4 · Shortest Path
25Shortest Path — Unit Weights 26Dijkstra's Algorithm 27Print the Path 28Shortest Distance in Binary Maze 29Path With Minimum Effort 30Cheapest Flights Within K Stops 31Ways to Arrive at Destination 32Bellman-Ford 33Floyd-Warshall 34City With Fewest Neighbors
5 · DSU & MST
35Disjoint Set Union 36Kruskal's MST 37Prim's MST 38Make Network Connected 39Accounts Merge 40Number of Islands II 41Making a Large Island 42Most Stones Removed 43Swim in Rising Water
6 · Advanced
44Bridges in Graph 45Articulation Points 46Kosaraju's SCC 47Tarjan's SCC
Σ
++Master cheatsheet
Phase 0

Neev — graph hai kya, aur usme chalte kaise 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.

1 2 3 4 5
5 nodes, 5 edges — undirected
Shabd jo baar-baar aayenge
ShabdMatlab
UndirectedEdge dono taraf chalti hai. 1—2 hai toh 1 se 2 bhi ja sakte ho, 2 se 1 bhi.
DirectedEdge ek taraf. 1→2 ka matlab 2→1 nahi. (Course prerequisites, task dependencies)
WeightedHar edge pe ek number — distance, cost, time.
DegreeNode se kitni edges lagi hain. Undirected me: sum of degrees = 2 × edges.
PathNodes ki sequence jahan har consecutive pair me edge ho.
CyclePath jo wahin lautkar aa jaye jahan se shuru hui thi.
ComponentEk "island" of nodes. Graph ke do tukde alag ho sakte hain — ye baat 90% log bhool jaate hain.
DAGDirected 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 = new int[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).

node neighbours 1 2 3 2 1 4 3 1 4 4 2 3 5 5 4
Q1 wale graph ki adjacency list
Java · adjacency list (yaad kar lo, har question me likhoge)
List<List<Integer>> adj = new ArrayList<>();
for (int i = 0; i < n; i++) adj.add(new ArrayList<>());

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 = new List[n];
for (int i = 0; i < n; i++) adj[i] = new ArrayList<>();

for (int[] e : edges) {           // e = {u, v, wt}
    adj[e[0]].add(new int[]{e[1], e[2]});
    adj[e[1]].add(new int[]{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).

1 2 3 4 5 lvl 0 lvl 1 lvl 1 lvl 2 lvl 3
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 = new LinkedList<>();
    q.add(src);
    vis[src] = true;               // MARK KARO PUSH KE WAQT

    while (!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, snapshot
    for (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 3 4 5 1st 2nd 4th 3rd 5th
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 = new ArrayDeque<>();
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
BFSDFS
StructureQueue (FIFO)Recursion / Stack (LIFO)
Orderlayer by layerek raasta poora, phir backtrack
Shortest path (unweighted)haan, guaranteednahi
Components ginnachalegachalega (aur chhota code)
Cycle detectchalegadirected graph me DFS zaroori
Topological sortKahnDFS + reverse
Space worst caseO(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, left
int[] 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}.
Q05

Number of Provinces

LC 547componentsadjacency matrix

Problem: n cities, aur ek n×n matrix isConnected jahan isConnected[i][j] = 1 matlab i aur j directly juday hain. Kitne "provinces" (connected groups) hain?

Soch

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).

0 1 2 province 1 3 4 province 2 5 province 3
Akela node bhi ek poora province hai — ye edge case mat bhoolna
Java · DFS
public int findCircleNum(int[][] isConnected) {
    int n = isConnected.length;
    boolean[] vis = new boolean[n];
    int count = 0;

    for (int i = 0; i < n; i++) {
        if (!vis[i]) {          // naya component mila
            count++;
            dfs(i, isConnected, vis);
        }
    }
    return count;
}

private void 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.

1 1 0 0 1 1 0 0 0 1 0 0 1 0 0 island 1 island 2 island 3
Diagonal se juda hua land alag island hai (4-dir rule)
Java · BFS flood
public int numIslands(char[][] grid) {
    int n = grid.length, m = grid[0].length, count = 0;
    boolean[][] vis = new boolean[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;
}

private void 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 = new LinkedList<>();
    q.add(new int[]{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(new int[]{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
public int[][] 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;
}

private void 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.

2 1 2 1 1 1 0 1 amber = t0 sources mint = t1 me sadenge dono sources ek saath queue me daale gaye
Multi-source BFS: 2 rotten oranges = 2 starting points, ek hi BFS
Java · multi-source BFS with level counting
public int orangesRotting(int[][] grid) {
    int n = grid.length, m = grid[0].length;
    Queue<int[]> q = new LinkedList<>();
    int fresh = 0;

    // STEP 1: saare sources queue me, aur fresh gino
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
            if (grid[i][j] == 2) q.add(new int[]{i, j});
            else if (grid[i][j] == 1) fresh++;
        }

    if (fresh == 0) return 0;          // *** edge case: koi fresh hi nahi ***

    int time = 0;
    int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};

    // STEP 2: level-wise BFS
    while (!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(new int[]{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
public int[][] updateMatrix(int[][] mat) {
    int n = mat.length, m = mat[0].length;
    int[][] dist = new int[n][m];
    boolean[][] vis = new boolean[n][m];
    Queue<int[]> q = new LinkedList<>();

    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            if (mat[i][j] == 0) { q.add(new int[]{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(new int[]{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
inputoutput (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:

  1. Boundary ke saare 'O' se DFS chalao → jo bhi mila, wo "safe" hai, mark kar do.
  2. 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."

X X X X X O O X X X O X X X O X coral = ghira hua → X banega mint = boundary tak pahunchta → safe, O hi rahega
(3,2) last row pe hai → boundary → uska poora region safe
Java
public void solve(char[][] board) {
    int n = board.length, m = board[0].length;
    boolean[][] safe = new boolean[n][m];

    // pehli aur aakhri column
    for (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 row
    for (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';
}

private void 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
public int numEnclaves(int[][] grid) {
    int n = grid.length, m = grid[0].length;
    boolean[][] vis = new boolean[n][m];
    Queue<int[]> q = new LinkedList<>();

    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(new int[]{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(new int[]{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.

1 1 1 (0,0)(0,1)(1,0) = 1 1 1 (0,0)(0,1)(1,0)
Alag jagah, same normalized signature → ek hi distinct island
Java
public int countDistinctIslands(int[][] grid) {
    int n = grid.length, m = grid[0].length;
    boolean[][] vis = new boolean[n][m];
    Set<String> shapes = new HashSet<>();

    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            if (!vis[i][j] && grid[i][j] == 1) {
                StringBuilder sb = new StringBuilder();
                dfs(i, j, i, j, grid, vis, sb);   // base = (i, j)
                shapes.add(sb.toString());
            }
    return shapes.size();
}

private void 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(' ');   // relative

    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 < 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
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
    Set<String> set = new HashSet<>(wordList);
    if (!set.contains(endWord)) return 0;      // *** edge case ***

    Queue<String> q = new LinkedList<>();
    q.add(beginWord);
    set.remove(beginWord);                      // visited ka kaam set hi kar raha hai
    int 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 = new String(arr);
                    if (set.contains(next)) {
                        set.remove(next);       // dobara visit na ho
                        q.add(next);
                    }
                }
                arr[pos] = original;            // *** restore karo ***
            }
        }
        steps++;
    }
    return 0;
}
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 aur nb != parent → cycle mil gaya
  • nb == parent → ignore, ye toh wahi edge hai jisse aaye the
0 1 2 3 coral edge = wahi jahan cycle pakda gaya 2 pe pahunche, padosi 3 already vis, aur 3 != parent(1) → cycle
Source 0. BFS 1 aur 3 dono ko level 1 pe daalta hai; 2 pe aakar 3 mil jata hai.
Java · BFS
public boolean isCycle(int V, List<List<Integer>> adj) {
    boolean[] vis = new boolean[V];
    for (int i = 0; i < V; i++)             // disconnected components!
        if (!vis[i] && bfsCheck(i, adj, vis)) return true;
    return false;
}

private boolean bfsCheck(int src, List<List<Integer>> adj, boolean[] vis) {
    Queue<int[]> q = new LinkedList<>();   // {node, parent}
    q.add(new int[]{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(new int[]{nb, node});
            } else if (nb != parent) {
                return true;                // visited + parent nahi = cycle
            }
        }
    }
    return false;
}
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
public boolean isCycle(int V, List<List<Integer>> adj) {
    boolean[] vis = new boolean[V];
    for (int i = 0; i < V; i++)
        if (!vis[i] && dfs(i, -1, adj, vis)) return true;
    return false;
}

private boolean 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)) return true;   // *** return propagate karo ***
        } else if (nb != parent) {
            return true;
        }
    }
    return false;
}
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.

0 1 0 1 4-cycle → bipartite ✓ 0 1 1 3-cycle → conflict ✗
Odd cycle me do padosi same colour pe aa hi jaate hain
Java · BFS colouring
public boolean isBipartite(int[][] graph) {
    int n = graph.length;
    int[] color = new int[n];
    Arrays.fill(color, -1);                 // -1 = abhi rangaa nahi

    for (int i = 0; i < n; i++) {
        if (color[i] != -1) continue;

        Queue<Integer> q = new LinkedList<>();
        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);
                } else if (color[nb] == color[node]) {
                    return false;                   // conflict
                }
            }
        }
    }
    return true;
}
Java · DFS version (same idea)
private boolean 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)) return false;
        } else if (color[nb] == col) return false;
    }
    return true;
}
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:

0 1 2 visited hai, par cycle nahi 0 1 2 asli cycle
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
public boolean isCyclic(int V, List<List<Integer>> adj) {
    boolean[] vis = new boolean[V], pathVis = new boolean[V];
    for (int i = 0; i < V; i++)
        if (!vis[i] && dfs(i, adj, vis, pathVis)) return true;
    return false;
}

private boolean 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)) return true;
        } else if (pathVis[nb]) {
            return true;                  // back edge = cycle
        }
    }

    pathVis[node] = false;                // *** BACKTRACK — ye line hi sab kuch hai ***
    return false;
}
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.
Khud try karo
  • 3-state wala version khud likho.
  • Self-loop 0→0 pe kya hoga? (pathVis[0] already true → cycle, sahi hai)
Q18

Eventual Safe States

LC 802cycle + memo

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
public List<Integer> eventualSafeNodes(int[][] graph) {
    int n = graph.length;
    boolean[] vis = new boolean[n], pathVis = new boolean[n], safe = new boolean[n];

    for (int i = 0; i < n; i++)
        if (!vis[i]) dfs(i, graph, vis, pathVis, safe);

    List<Integer> res = new ArrayList<>();
    for (int i = 0; i < n; i++) if (safe[i]) res.add(i);
    return res;                          // 0..n-1 loop se already sorted
}

private boolean 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)) return true;   // cycle mila
        } else if (pathVis[nb]) return true;
    }

    pathVis[node] = false;
    safe[node] = true;                   // yahan tak pahunche = koi cycle nahi mila
    return false;
}
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
5 4 2 3 1 0 valid order: 5 4 2 3 1 0  (ya 4 5 2 3 0 1 — kai ho sakte hain)
Har teer bayein se dayein — yahi topological order ka matlab hai
Java · DFS + stack
public int[] topoSort(int V, List<List<Integer>> adj) {
    boolean[] vis = new boolean[V];
    Deque<Integer> st = new ArrayDeque<>();

    for (int i = 0; i < V; i++) if (!vis[i]) dfs(i, adj, vis, st);

    int[] res = new int[V];
    int idx = 0;
    while (!st.isEmpty()) res[idx++] = st.pop();   // ulta padho
    return res;
}

private void 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)
public int[] topoSort(int V, List<List<Integer>> adj) {
    int[] indeg = new int[V];
    for (int u = 0; u < V; u++)
        for (int v : adj.get(u)) indeg[v]++;

    Queue<Integer> q = new LinkedList<>();
    for (int i = 0; i < V; i++) if (indeg[i] == 0) q.add(i);

    int[] res = new int[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)
Q21

Cycle in Directed — Kahn

GFGcounting trick

Q17 (DFS + pathVis) ka BFS alternative. Aur code chhota hai.

Kyun kaam karta hai

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
public boolean isCyclic(int V, List<List<Integer>> adj) {
    int[] indeg = new int[V];
    for (int u = 0; u < V; u++) for (int v : adj.get(u)) indeg[v]++;

    Queue<Integer> q = new LinkedList<>();
    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)
public int[] findOrder(int numCourses, int[][] prerequisites) {
    int n = numCourses;
    List<List<Integer>> adj = new ArrayList<>();
    for (int i = 0; i < n; i++) adj.add(new ArrayList<>());

    int[] indeg = new int[n];
    for (int[] p : prerequisites) {
        adj.get(p[1]).add(p[0]);      // p[1] pehle → p[0]
        indeg[p[0]]++;
    }

    Queue<Integer> q = new LinkedList<>();
    for (int i = 0; i < n; i++) if (indeg[i] == 0) q.add(i);

    int[] res = new int[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 : new int[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.

b a a a b c d a b c a w1[0]=b, w2[0]=a alag → b→a pehle 3 same, index 3 pe d vs a alag → d→a
Har consecutive pair se zyada se zyada ek hi edge nikalti hai
Java
public String findOrder(String[] dict, int N, int K) {
    List<List<Integer>> adj = new ArrayList<>();
    for (int i = 0; i < K; i++) adj.add(new ArrayList<>());
    int[] indeg = new int[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 = new LinkedList<>();
    for (int i = 0; i < K; i++) if (indeg[i] == 0) q.add(i);

    StringBuilder sb = new StringBuilder();
    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
public int[] shortestPath(int V, int E, int[][] edges) {
    List<int[]>[] adj = new List[V];
    for (int i = 0; i < V; i++) adj[i] = new ArrayList<>();
    for (int[] e : edges) adj[e[0]].add(new int[]{e[1], e[2]});   // u, v, wt

    // 1) topo order
    boolean[] vis = new boolean[V];
    Deque<Integer> st = new ArrayDeque<>();
    for (int i = 0; i < V; i++) if (!vis[i]) topo(i, adj, vis, st);

    // 2) relax in topo order
    int[] dist = new int[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 nahi

        for (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;
}

private void 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:

SituationAlgorithmTime
Unweighted (ya sab weights = 1)BFSO(V+E)
Weights 0 aur 1 hi hain0-1 BFS (Deque)O(V+E)
DAG, koi bhi weightTopo + relax (Q24)O(V+E)
Positive weights, single sourceDijkstraO(E log V)
Negative weights ho sakte hainBellman-FordO(V×E)
Negative cycle detect karni haiBellman-FordO(V×E)
All pairs, chhota V (≤ 400)Floyd-WarshallO(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
public int[] shortestPath(List<List<Integer>> adj, int V, int src) {
    int[] dist = new int[V];
    Arrays.fill(dist, -1);
    dist[src] = 0;

    Queue<Integer> q = new LinkedList<>();
    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.

4 1 2 5 8 0 1 2 3 d=0 d=3 d=1 d=8
0→1 direct 4 hai, par 0→2→1 sirf 3. Greedy pop order isko pakad leta hai.
Java · Dijkstra (ye poora yaad karo)
public int[] dijkstra(int V, List<int[]>[] adj, int src) {
    int[] dist = new int[V];
    Arrays.fill(dist, Integer.MAX_VALUE);
    dist[src] = 0;

    // {distance, node} — distance pe sort
    PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
    pq.add(new int[]{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(new int[]{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.
  • LC 743 (Network Delay Time) — seedha Dijkstra, answer max(dist) hai.
Q27

Print the Path

GFGparent array

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
public List<Integer> shortestPath(int n, int m, int[][] edges) {
    List<int[]>[] adj = new List[n + 1];
    for (int i = 1; i <= n; i++) adj[i] = new ArrayList<>();
    for (int[] e : edges) {
        adj[e[0]].add(new int[]{e[1], e[2]});
        adj[e[1]].add(new int[]{e[0], e[2]});
    }

    int[] dist = new int[n + 1], parent = new int[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 = new PriorityQueue<>((a, b) -> a[0] - b[0]);
    pq.add(new int[]{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(new int[]{dist[v], v});
            }
        }
    }

    List<Integer> path = new ArrayList<>();
    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
public int shortestPath(int[][] grid, int[] src, int[] dest) {
    if (src[0] == dest[0] && src[1] == dest[1]) return 0;
    int n = grid.length, m = grid[0].length;

    int[][] dist = new int[n][m];
    for (int[] row : dist) Arrays.fill(row, Integer.MAX_VALUE);
    dist[src[0]][src[1]] = 0;

    Queue<int[]> q = new LinkedList<>();
    q.add(new int[]{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(new int[]{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:

Normal Dijkstra: newCost = dist[u] + wt
Yahan: newCost = max(dist[u], |height[u] - height[v]|)

Baaki poora Dijkstra bilkul same. Ye "minimax path" pattern hai — ek baar dekh lo toh har jagah pehchaan loge.

Java
public int minimumEffortPath(int[][] heights) {
    int n = heights.length, m = heights[0].length;
    int[][] eff = new int[n][m];
    for (int[] row : eff) Arrays.fill(row, Integer.MAX_VALUE);
    eff[0][0] = 0;

    // {effort, row, col}
    PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
    pq.add(new int[]{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 do
        if (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(new int[]{newEff, nr, nc});
            }
        }
    }
    return 0;
}
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)
public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
    List<int[]>[] adj = new List[n];
    for (int i = 0; i < n; i++) adj[i] = new ArrayList<>();
    for (int[] f : flights) adj[f[0]].add(new int[]{f[1], f[2]});

    int[] dist = new int[n];
    Arrays.fill(dist, Integer.MAX_VALUE);
    dist[src] = 0;

    Queue<int[]> q = new LinkedList<>();   // {node, cost}
    q.add(new int[]{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(new int[]{v, cost + w});
                }
            }
        }
        stops++;
    }
    return dist[dst] == Integer.MAX_VALUE ? -1 : dist[dst];
}
Java · Bellman-Ford version (aur bhi saaf)
public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
    int[] dist = new int[n];
    Arrays.fill(dist, Integer.MAX_VALUE);
    dist[src] = 0;

    for (int round = 0; round <= k; round++) {     // k+1 edges tak
        int[] 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.
Khud try karo
  • n=3, flights=[[0,1,100],[1,2,100],[0,2,500]], src=0, dst=2, k=0 → 500. k=1 → 200. Dono trace karo.
  • 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
public int countPaths(int n, int[][] roads) {
    final int MOD = 1_000_000_007;
    List<long[]>[] adj = new List[n];
    for (int i = 0; i < n; i++) adj[i] = new ArrayList<>();
    for (int[] r : roads) {
        adj[r[0]].add(new long[]{r[1], r[2]});
        adj[r[1]].add(new long[]{r[0], r[2]});
    }

    long[] dist = new long[n];
    long[] ways = new long[n];
    Arrays.fill(dist, Long.MAX_VALUE);
    dist[0] = 0;
    ways[0] = 1;

    PriorityQueue<long[]> pq = new PriorityQueue<>((a, b) -> Long.compare(a[0], b[0]));
    pq.add(new long[]{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(new long[]{dist[v], v});
            } else if (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
public int[] bellmanFord(int V, int[][] edges, int src) {
    int[] dist = new int[V];
    Arrays.fill(dist, (int) 1e8);          // MAX_VALUE ki jagah bada sentinel
    dist[src] = 0;

    // V-1 rounds
    for (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 cycle
    for (int[] e : edges) {
        int u = e[0], v = e[1], w = e[2];
        if (dist[u] != (int) 1e8 && dist[u] + w < dist[v]) {
            return new int[]{-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?"

dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])

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
public void shortestDistance(int[][] dist) {
    int n = dist.length;

    // -1 (no edge) ko bada sentinel banao
    for (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] < 0
    for (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
public int findTheCity(int n, int[][] edges, int distanceThreshold) {
    int[][] dist = new int[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.

1 2 3 4 pehle: find(4) me 3 hops → 1 2 3 4 baad me: sab seedhe root pe
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)
class DSU {
    int[] parent, size;
    int components;

    DSU(int n) {
        parent = new int[n];
        size = new int[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) return false;              // already same group

        if (size[ra] < size[rb]) { int t = ra; ra = rb; rb = t; }
        parent[rb] = ra;                          // chhota bade ke neeche
        size[ra] += size[rb];
        components--;
        return true;
    }

    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
public int spanningTree(int V, int[][] edges) {   // edges: {u, v, wt}
    Arrays.sort(edges, (a, b) -> a[2] - b[2]);

    DSU dsu = new DSU(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
public int spanningTree(int V, List<int[]>[] adj) {
    boolean[] inMST = new boolean[V];
    PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);  // {wt, node}
    pq.add(new int[]{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(new int[]{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.
KruskalPrim
StructureDSU + sorted edgesPriorityQueue
TimeO(E log E)O(E log V)
Input suitsedge listadjacency list
Behtar kabsparse graphdense graph
MST edges chahiyeseedha mil jate hainparent 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.
  • Components = kitne alag tukde hain. Unhe jodne ke liye components - 1 cables chahiye.

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
public int makeConnected(int n, int[][] connections) {
    if (connections.length < n - 1) return -1;   // cables hi kam hain

    DSU dsu = new DSU(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.

  1. 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).
  2. Ab har email ko uske account ke find() root ke group me daal do.
  3. Har group ke emails sort karo, aage naam laga do.
Java
public List<List<String>> accountsMerge(List<List<String>> accounts) {
    int n = accounts.size();
    DSU dsu = new DSU(n);
    Map<String, Integer> emailToIdx = new HashMap<>();

    // STEP 1: same email = same insaan → union
    for (int i = 0; i < n; i++) {
        for (int j = 1; j < accounts.get(i).size(); j++) {   // j=0 naam hai
            String 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 karo
    Map<Integer, List<String>> groups = new HashMap<>();
    for (Map.Entry<String, Integer> en : emailToIdx.entrySet()) {
        int root = dsu.find(en.getValue());
        groups.computeIfAbsent(root, x -> new ArrayList<>()).add(en.getKey());
    }

    // STEP 3: sort + naam lagao
    List<List<String>> res = new ArrayList<>();
    for (Map.Entry<Integer, List<String>> en : groups.entrySet()) {
        List<String> emails = en.getValue();
        Collections.sort(emails);
        List<String> row = new ArrayList<>();
        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 pe count-- (do islands mil ke ek ban gaye).

count 1 count 2 count 1 (2 unions) naya cell dono islands ko jod deta hai
2 + 1 - 2 = 1. Ek naya cell do islands ko merge kar sakta hai.
Java
public List<Integer> numIslands2(int n, int m, int[][] operators) {
    DSU dsu = new DSU(n * m);
    boolean[][] land = new boolean[n][m];
    List<Integer> res = new ArrayList<>();
    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 ek 0 ko 1 bana sakte ho. Sabse bada possible island ka size?

Soch — do pass
  1. Pass 1: saare existing islands ko DSU se jod do. Ab har root ke paas uske island ka size hai.
  2. 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
public int largestIsland(int[][] grid) {
    int n = grid.length;
    DSU dsu = new DSU(n * n);
    int[] dr = {-1, 0, 1, 0}, dc = {0, 1, 0, -1};

    // PASS 1: existing islands jodo
    for (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 dekho
    int 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 = new HashSet<>();
            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 nahi
    for (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
public int removeStones(int[][] stones) {
    DSU dsu = new DSU(20002);           // rows 0..10000, cols 10001..20001
    Set<Integer> used = new HashSet<>();

    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 = new HashSet<>();
    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
public int swimInWater(int[][] grid) {
    int n = grid.length;
    int[][] best = new int[n][n];
    for (int[] row : best) Arrays.fill(row, Integer.MAX_VALUE);
    best[0][0] = grid[0][0];

    PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
    pq.add(new int[]{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(new int[]{nt, nr, nc});
            }
        }
    }
    return -1;
}
Java · DSU style (elevation order me cells "kholo")
public int swimInWater(int[][] grid) {
    int n = grid.length;
    int[] pos = new int[n * n];              // elevation -> cell index
    for (int r = 0; r < n; r++)
        for (int c = 0; c < n; c++) pos[grid[r][c]] = r * n + c;

    DSU dsu = new DSU(n * n);
    boolean[] open = new boolean[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.)

0 1 2 3 4 5 1—3 = bridge cycle ke andar koi bridge nahi hoti
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
private int timer = 0;

public List<List<Integer>> criticalConnections(int n, List<List<Integer>> connections) {
    List<List<Integer>> adj = new ArrayList<>();
    for (int i = 0; i < n; i++) adj.add(new ArrayList<>());
    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 = new int[n], low = new int[n];
    boolean[] vis = new boolean[n];
    List<List<Integer>> bridges = new ArrayList<>();

    dfs(0, -1, adj, vis, tin, low, bridges);
    return bridges;
}

private void 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 se

            if (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
private int timer = 0;

public List<Integer> articulationPoints(int V, List<List<Integer>> adj) {
    int[] tin = new int[V], low = new int[V];
    boolean[] vis = new boolean[V], isAP = new boolean[V];

    for (int i = 0; i < V; i++)
        if (!vis[i]) dfs(i, -1, adj, vis, tin, low, isAP);

    List<Integer> res = new ArrayList<>();
    for (int i = 0; i < V; i++) if (isAP[i]) res.add(i);
    return res.isEmpty() ? Arrays.asList(-1) : res;
}

private void 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
  1. DFS chalao, finish time ke hisaab se stack me daalo (bilkul Q19 topo sort jaisa).
  2. Graph ko reverse karo — har edge u→v ko v→u bana do.
  3. 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
public int kosaraju(int V, List<List<Integer>> adj) {
    // STEP 1: finish order
    boolean[] vis = new boolean[V];
    Deque<Integer> st = new ArrayDeque<>();
    for (int i = 0; i < V; i++) if (!vis[i]) dfs1(i, adj, vis, st);

    // STEP 2: transpose
    List<List<Integer>> rev = new ArrayList<>();
    for (int i = 0; i < V; i++) rev.add(new ArrayList<>());
    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 reversed
    Arrays.fill(vis, false);
    int scc = 0;
    while (!st.isEmpty()) {
        int node = st.pop();
        if (!vis[node]) { scc++; dfs2(node, rev, vis); }
    }
    return scc;
}

private void 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
}

private void 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
private int timer = 0;
private int[] tin, low;
private boolean[] onStack;
private Deque<Integer> st;
private List<List<Integer>> sccs;

public List<List<Integer>> tarjan(int V, List<List<Integer>> adj) {
    tin = new int[V]; low = new int[V];
    Arrays.fill(tin, -1);
    onStack = new boolean[V];
    st = new ArrayDeque<>();
    sccs = new ArrayList<>();

    for (int i = 0; i < V; i++) if (tin[i] == -1) dfs(i, adj);
    return sccs;
}

private void 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]);
        } else if (onStack[v]) {                   // *** stack pe hai tabhi ***
            low[u] = Math.min(low[u], tin[v]);
        }
    }

    if (low[u] == tin[u]) {                        // SCC root
        List<Integer> comp = new ArrayList<>();
        while (true) {
            int w = st.pop();
            onStack[w] = false;
            comp.add(w);
            if (w == u) break;
        }
        sccs.add(comp);
    }
}
KosarajuTarjan
DFS passes21
Reverse graphchahiyenahi chahiye
TimeO(V+E)O(V+E)
Yaad karnaaasanmushkil
Interview meKosaraju boloTarjan 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 dikheYe sochoQ
"kitne groups / islands / provinces"DFS/BFS components, ya DSU5, 6, 38
"minimum steps / seconds / moves" (unweighted)BFS8, 13, 25, 28
"minimum cost / distance" (weighted, positive)Dijkstra26, 29
negative weightsBellman-Ford32
"har pair ke beech distance"Floyd-Warshall33, 34
DAG + shortest/longest pathtopo sort + relax24
"kya order me kar sakte hain" / prerequisitestopo sort (Kahn)20, 22, 23
"kya cycle hai"undirected: parent · directed: pathVis ya Kahn14, 17, 21
"do groups me baanto"bipartite check16
"sab jodne ki minimum cost"MST — Kruskal ya Prim36, 37
edges ek-ek karke aa rahi hain / baar-baar "connected?"DSU35, 40
"minimize the maximum" on a pathDijkstra-with-max, ya DSU sorted, ya binary search29, 43
"critical connection" / "network toot jayega"bridges / articulation points44, 45
directed, "mutually reachable" groupsSCC — Kosaraju46
2 · Complexity summary
AlgorithmTimeSpaceConstraint
BFS / DFSO(V + E)O(V)—
Topological sortO(V + E)O(V)DAG hona chahiye
DijkstraO(E log V)O(V + E)weights ≥ 0
Bellman-FordO(V × E)O(V)negative ok, neg-cycle detect
Floyd-WarshallO(V³)O(V²)V ≤ 400ish
KruskalO(E log E)O(V)undirected connected
PrimO(E log V)O(V + E)undirected connected
DSU (per op)O(α(n)) ≈ O(1)O(n)dono optimizations lagao
Bridges / AP / Tarjan SCCO(V + E)O(V)—
KosarajuO(V + E)O(V + E)directed
3 · Debug checklist — code galat hai toh yahan dekho
LakshanSambhavit wajah
TLE ya infinite loopvisited push ke waqt mark nahi kiya (BFS); Dijkstra me stale-entry skip nahi
Count 1 zyada / kamcount++ traversal ke andar hai (driver loop me hona chahiye); level counter ka off-by-one
Disconnected graph pe galatdriver loop hi nahi hai — for i in 0..V-1 if(!vis[i])
Directed cycle detect nahi huipathVis[node] = false backtrack line missing
DFS true return nahi kar rahaif (dfs(...)) return true; ki jagah sirf dfs(...) likha
Overflow / bakwaas negative distancesMAX_VALUE + wt; sentinel 1e9 use karo aur unreachable pe skip
Floyd-Warshall galatk ka loop bahar nahi hai
Prim ka MST mehnga aa rahainMST check push pe kar diya, pop pe hona chahiye
DSU slowpath compression me assignment nahi (parent[x] = find(...))
Grid solution index errorboundary check <n vs <=n; rows/cols ulat gaye
Course Schedule ulta answeredge 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(new int[]{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 → minimax
        if (nd < dist[v]) {
            dist[v] = nd;
            pq.add(new int[]{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.