Progress
💡
Why does this topic matter?
Matrix problems appear in virtually every major tech interview — Google, Amazon, Meta, Microsoft all love them. They test your ability to think spatially, manage 2D state, and apply graph algorithms (DFS/BFS) to a grid structure. Spiral traversal, island counting, BFS distance propagation, in-place transformations, and binary search on sorted matrices are near-guaranteed question types. Mastering the 4 matrix patterns below covers ~90% of all matrix interview questions.
🔗
How it connects: Lecture 8 (Arrays) gave you 1D in-place manipulation — the same mindset extends to 2D. Lecture 13 (HashMap) will appear inside DFS for visited-cell tracking. Lecture 15 (Trees) and Lecture 17 (Graphs) are natural extensions — a grid IS a graph where each cell has up to 4 neighbours. Every pattern here maps directly to tree/graph problems.

🧼 Introduction to Matrix Problems

Before writing a single line of code, let us build the correct mental model. A matrix is just a 2D array declared as int[][] grid with m rows and n columns. Every cell is identified by its row index r and column index c.

The single most important insight in this entire lecture is:

🌟
A 2D matrix is secretly a graph.
Each cell grid[r][c] is a node. Two cells are neighbours (connected by an edge) if they share a side (up, down, left, right). Once you see the matrix as a graph, every graph algorithm — DFS, BFS, shortest path — instantly applies. This is the unlock.

📈 The Grid Mental Model

Imagine you are standing on a cell (r, c) in the grid. You can move in at most 4 directions:

(r-1, c) ← UP | (r, c-1) ← LEFT —— (r, c) —— RIGHT → (r, c+1) | (r+1, c) ← DOWN Canonical 4-direction array (memorise this!): int[][] dirs = { {-1,0}, {1,0}, {0,-1}, {0,1} }; // UP DOWN LEFT RIGHT Bounds check before accessing neighbour: int nr = r + d[0], nc = c + d[1]; if (nr >= 0 && nr < m && nc >= 0 && nc < n) { /* safe to access */ }
Always check bounds FIRST. The most common matrix bug is accessing grid[r][c] without verifying 0 ≤ r < m and 0 ≤ c < n. In DFS, bounds check must be the very first base case — before checking the cell value. Out-of-bounds access throws ArrayIndexOutOfBoundsException silently in many LeetCode environments.

📋 Matrix Anatomy in Java

☕ Java · Matrix Fundamentals
// Declaration
int[][] grid = new int[m][n];   // m rows, n columns, all 0
char[][] board = new char[m][n]; // for island problems (often '0' or '1')

// Dimensions
int m = grid.length;          // number of ROWS
int n = grid[0].length;       // number of COLUMNS

// Access: O(1)
grid[r][c];                   // row r, column c

// Traversal (row-major order): O(m*n)
for (int r = 0; r < m; r++)
    for (int c = 0; c < n; c++)
        process(grid[r][c]);

// Reusable inBounds helper (write this at the top of every grid solution)
boolean inBounds(int r, int c) {
    return r >= 0 && r < m && c >= 0 && c < n;
}

// 4-direction expansion (use this template ALWAYS)
int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}};
for (int[] d : dirs) {
    int nr = r + d[0], nc = c + d[1];
    if (inBounds(nr, nc)) { /* process neighbour */ }
}
🎯
Pattern Recognition Table — Read this first before any matrix problem:
Signal Phrase in Problem Pattern to Apply Key Algorithm
"spiral order", "layer by layer", "peel" Boundary / Spiral Walk 4-pointer shrink
"in place", "O(1) space" + state changes In-Place State Machine Sentinel encoding
"connected cells", "island", "flood fill", "region" Grid DFS Recursive flood fill
"shortest distance", "nearest", "minimum time" Grid BFS Multi-source BFS
"sorted rows and columns", "search in matrix" 2D Binary Search Corner walk O(m+n)

🎯 The 4 Core Matrix Patterns

Pattern 1 — Boundary / Spiral Traversal

When to use: Problems that ask you to visit cells in a specific order that "peels" the matrix from outside in (spiral, layer by layer, zigzag).

Core idea: Maintain 4 boundary pointers — top, bottom, left, right — and shrink them inward after traversing each side. Keep going while top ≤ bottom and left ≤ right.

Matrix: [[1, 2, 3], [4, 5, 6], [7, 8, 9]] Round 1: top=0,bot=2,lft=0,rgt=2 → traverse top row: 1, 2, 3 (top++) top=1 ↓ traverse right col: 6, 9 (rgt--) rgt=1 ← traverse bot row: 8, 7 (bot--) bot=1 ↑ traverse left col: 4 (lft++) lft=1 Round 2: top=1,bot=1,lft=1,rgt=1 → traverse top row: 5 (top++) top=2 > bot=1 → STOP Result: [1, 2, 3, 6, 9, 8, 7, 4, 5] ✓
☕ Java · Spiral Traversal Template (LC 54)
List<Integer> spiralOrder(int[][] matrix) {
    List<Integer> res = new ArrayList<>();
    int top = 0, bot = matrix.length - 1;
    int lft = 0, rgt = matrix[0].length - 1;

    while (top <= bot && lft <= rgt) {
        // → traverse top row left-to-right
        for (int c = lft; c <= rgt; c++) res.add(matrix[top][c]);
        top++;

        // ↓ traverse right column top-to-bottom
        for (int r = top; r <= bot; r++) res.add(matrix[r][rgt]);
        rgt--;

        // ← traverse bottom row right-to-left (guard: rows remain)
        if (top <= bot) {
            for (int c = rgt; c >= lft; c--) res.add(matrix[bot][c]);
            bot--;
        }

        // ↑ traverse left column bottom-to-top (guard: cols remain)
        if (lft <= rgt) {
            for (int r = bot; r >= top; r--) res.add(matrix[r][lft]);
            lft++;
        }
    }
    return res;
}
// Time: O(m*n) — every cell visited exactly once
// Space: O(1) extra (result array not counted)
🔭
Why the two guards (if top ≤ bot and if lft ≤ rgt)?
After traversing the top row and right column, the remaining rows/columns might have collapsed. For example, a single-row matrix: top becomes 1 which is > bot=0, so the bottom-row traversal would re-collect cells we already visited. The guards prevent this double-counting.

Pattern 2 — In-Place State Machine

When to use: Problems requiring O(1) extra space where you must record which cells have been "marked" or "changed" without using a separate array.

Core idea: Encode two states in one cell value. Use sentinel values (like -1, 2, or a sign flip) to represent "this cell is scheduled to change" without actually changing it yet. Make changes in a second pass once all decisions are final.

Classic example: Rotate Image (LC 48) — 90° clockwise = Transpose + Reverse each row.

Step 1: Transpose (swap matrix[i][j] with matrix[j][i]) [[1,2,3], [[1,4,7], [4,5,6], → [2,5,8], [7,8,9]] [3,6,9]] Step 2: Reverse each row [[1,4,7], [[7,4,1], [2,5,8], → [8,5,2], [3,6,9]] [9,6,3]] ✓ (90° clockwise)
☕ Java · Rotate Image (LC 48) — Transpose + Reverse
void rotate(int[][] m) {
    int n = m.length;

    // Step 1: Transpose — swap across main diagonal (i,j) ↔ (j,i)
    for (int i = 0; i < n; i++)
        for (int j = i + 1; j < n; j++) {
            int tmp = m[i][j]; m[i][j] = m[j][i]; m[j][i] = tmp;
        }

    // Step 2: Reverse each row
    for (int i = 0; i < n; i++) {
        int lo = 0, hi = n - 1;
        while (lo < hi) {
            int tmp = m[i][lo]; m[i][lo] = m[i][hi]; m[i][hi] = tmp;
            lo++; hi--;
        }
    }
}
// Time: O(n²)  |  Space: O(1)
// Counter-clockwise 90° = Transpose + Reverse each COLUMN
// 180° = Reverse all rows + Reverse each row
☕ Java · Set Matrix Zeroes (LC 73) — First Row/Col as Sentinels
void setZeroes(int[][] m) {
    int rows = m.length, cols = m[0].length;
    boolean row0 = false, col0 = false;

    // Pass 1: does row 0 / col 0 itself contain a zero?
    for (int c = 0; c < cols; c++) if (m[0][c] == 0) row0 = true;
    for (int r = 0; r < rows; r++) if (m[r][0] == 0) col0 = true;

    // Pass 2: mark row 0 and col 0 as sentinels for inner cells
    for (int r = 1; r < rows; r++)
        for (int c = 1; c < cols; c++)
            if (m[r][c] == 0) { m[r][0] = 0; m[0][c] = 0; }

    // Pass 3: use sentinels to zero out inner cells
    for (int r = 1; r < rows; r++)
        for (int c = 1; c < cols; c++)
            if (m[r][0] == 0 || m[0][c] == 0) m[r][c] = 0;

    // Pass 4: zero out row 0 and col 0 based on original flags
    if (row0) for (int c = 0; c < cols; c++) m[0][c] = 0;
    if (col0) for (int r = 0; r < rows; r++) m[r][0] = 0;
}
// Time: O(m*n)  |  Space: O(1)
// KEY: Why handle row0/col0 with separate flags?
// Because we reuse them as sentinel storage — if we zeroed them first,
// we'd corrupt our own sentinel data.

Pattern 3 — Grid DFS (Flood Fill / Connected Components)

When to use: Count connected components (islands), mark/explore regions, check reachability. Use DFS when you need to visit ALL connected cells and order doesn't matter.

Core idea: Treat the grid as a graph. From any cell, recursively explore all 4 neighbours. Mark cells as "visited" in-place (by changing their value) to avoid revisiting.

Flood Fill DFS — "Sinking the island": Start: grid[0][0] = '1' After DFS from (0,0): [['1','1','0','0'], [['2','2','0','0'], ['1','0','0','1'], → ['2','0','0','1'], ['0','0','1','1']] ['0','0','1','1']] island 1 sunk (count=1). Next unvisited '1': (1,3) → count=2 Next: (2,2) connected to (2,3) → count=3. Total islands = 3
☕ Java · Grid DFS Template (Flood Fill)
int m, n;

int numIslands(char[][] grid) {
    m = grid.length; n = grid[0].length;
    int count = 0;
    for (int r = 0; r < m; r++)
        for (int c = 0; c < n; c++)
            if (grid[r][c] == '1') { count++; dfs(grid, r, c); }
    return count;
}

void dfs(char[][] grid, int r, int c) {
    // Base cases — ALWAYS bounds check first
    if (r < 0 || r >= m || c < 0 || c >= n) return;
    if (grid[r][c] != '1') return;     // water or already visited

    grid[r][c] = '2';                   // mark visited in-place (sink it)

    dfs(grid, r-1, c); // up
    dfs(grid, r+1, c); // down
    dfs(grid, r, c-1); // left
    dfs(grid, r, c+1); // right
}
// Time: O(m*n)  |  Space: O(m*n) call stack worst case
// Interview follow-up: "What if the grid is huge and DFS stack overflows?"
// Answer: Use BFS (iterative queue) — same O(m*n), no stack overflow risk.

Pattern 4 — Grid BFS (Multi-Source Shortest Path)

When to use: Find shortest distance from some source cells to all other cells. BFS guarantees the shortest path in an unweighted graph — this is its defining superpower over DFS.

Multi-source BFS key insight: Instead of running BFS from each source cell one by one (which would be O((m*n)²)), seed the queue with ALL source cells simultaneously. BFS then propagates distances outward level by level in a single O(m*n) pass.

Multi-Source BFS — 01 Matrix (distance to nearest 0): Input: Queue seed (all 0s): After BFS: [[0,0,0], (0,0),(0,1),(0,2) [[0,0,0], [0,1,0], → (1,0),(1,2) → [0,1,0], [1,1,1]] ↓ expand level by level [1,2,1]] Minute 1: expand to all unvisited neighbours of queue → (2,0),(2,2) get dist=1 Minute 2: expand to (2,1) which gets dist=2. Queue empty. Done.
☕ Java · Multi-Source BFS Template (01 Matrix LC 542)
int[][] updateMatrix(int[][] mat) {
    int m = mat.length, n = mat[0].length;
    int[][] dist = new int[m][n];
    Queue<int[]> q = new LinkedList<>();

    // Seed: enqueue ALL 0-cells; mark 1-cells as unvisited (dist=-1)
    for (int r = 0; r < m; r++)
        for (int c = 0; c < n; c++) {
            if (mat[r][c] == 0) { dist[r][c] = 0; q.offer(new int[]{r,c}); }
            else dist[r][c] = -1;
        }

    int[][] dirs = {{-1,0},{1,0},{0,-1},{0,1}};
    while (!q.isEmpty()) {
        int[] curr = q.poll();
        for (int[] d : dirs) {
            int nr = curr[0]+d[0], nc = curr[1]+d[1];
            if (nr>=0 && nr<m && nc>=0 && nc<n && dist[nr][nc]==-1) {
                dist[nr][nc] = dist[curr[0]][curr[1]] + 1;
                q.offer(new int[]{nr, nc});
            }
        }
    }
    return dist;
}
// Time: O(m*n)  |  Space: O(m*n)
// Why dist=-1 and not Integer.MAX_VALUE? Avoids overflow on +1 and
// serves as the "unvisited" sentinel naturally.

Pattern 5 — 2D Binary Search (Corner Walk)

When to use: Searching in a matrix where rows are sorted left-to-right AND columns are sorted top-to-bottom. Brute force O(m*n) is too slow; the sorted structure lets us do O(m+n).

Core idea: Start at the top-right corner. This cell has a magical property: it is the maximum of its row and the minimum of its column. So we can make a definitive decision at every step — either eliminate this row (go down) or this column (go left).

Matrix (rows sorted →, cols sorted ↓): target = 5 [[ 1, 4, 7, 11], Start: (0,3)=11 > 5 → c-- (eliminate col 3) [ 2, 5, 8, 12], (0,2)=7 > 5 → c-- (eliminate col 2) [ 3, 6, 9, 16], (0,1)=4 < 5 → r++ (eliminate row 0) [10, 13, 14, 17]] (1,1)=5 == 5 → FOUND! Each step eliminates one full row OR column → at most m+n steps total → O(m+n)
☕ Java · Corner Walk (LC 240 Search 2D Matrix II)
boolean searchMatrix(int[][] matrix, int target) {
    int r = 0, c = matrix[0].length - 1;   // top-right corner
    while (r < matrix.length && c >= 0) {
        if      (matrix[r][c] == target) return true;
        else if (matrix[r][c] >  target) c--;  // too large → go left
        else                             r++;  // too small → go down
    }
    return false;
}
// Time: O(m+n)  |  Space: O(1)

// LC 74 vs LC 240:
// LC 74: Fully sorted (row-major), last of row < first of next row
//   → treat as 1D, use classic binary search: O(log(m*n))
// LC 240: Only row-sorted AND col-sorted independently
//   → need corner walk: O(m+n)   ← this solution
Why top-right and not top-left or bottom-right?
Top-left: both neighbours (right and down) are larger — we can never eliminate anything when target is larger.
Bottom-right: both neighbours (left and up) are smaller — same problem when target is smaller.
Top-right is the sweet spot: left neighbour is smaller (eliminate column if curr is too large), down neighbour is larger (eliminate row if curr is too small). One clear decision at every step.

💪 In-Lecture Practice Problems

Work through these in order. Each card covers one of the 4 core patterns. Try to solve before revealing the solution. The dry runs are your best teacher.

Problem 01 · Boundary Traversal
Spiral Matrix
MediumGoogleAmazonMicrosoftBoundary Walk

Given an m×n matrix, return all elements in spiral order.

Input: [[1,2,3],[4,5,6],[7,8,9]] Output: [1,2,3,6,9,8,7,4,5]

Think of peeling an onion. Traverse the outermost ring (top row → right col ↓ bottom row ← left col ↑), then move the four boundaries inward and repeat. Always guard the bottom and left passes for odd-shaped matrices.

Full Solution + Dry Run
☕ Java · Four-Pointer Spiral
List<Integer> spiralOrder(int[][] mat) {
    List<Integer> res = new ArrayList<>();
    int top=0, bot=mat.length-1, lft=0, rgt=mat[0].length-1;
    while (top <= bot && lft <= rgt) {
        for (int c=lft; c<=rgt; c++) res.add(mat[top][c]); top++;
        for (int r=top; r<=bot; r++) res.add(mat[r][rgt]);   rgt--;
        if (top <= bot) { for (int c=rgt; c>=lft; c--) res.add(mat[bot][c]); bot--; }
        if (lft <= rgt) { for (int r=bot; r>=top; r--) res.add(mat[r][lft]); lft++; }
    }
    return res;
}
TimeO(m*n)
SpaceO(1)
Problem 02 · In-Place Rotation
Rotate Image
MediumAmazonMicrosoftAppleTranspose + Reverse

Rotate an n×n matrix 90° clockwise in place with O(1) extra space.

Input: [[1,2,3],[4,5,6],[7,8,9]] Output: [[7,4,1],[8,5,2],[9,6,3]]

Transpose the matrix (swap [i][j] with [j][i]), then reverse each row. The mathematical proof: rotating 90° clockwise maps position (r,c) to (c, n-1-r). Transposing gives (c,r), reversing each row turns (c,r) into (c,n-1-r). QED.

Full Solution + Step-by-Step Proof
☕ Java · Rotate Image
void rotate(int[][] m) {
    int n = m.length;
    for (int i=0; i<n; i++)
        for (int j=i+1; j<n; j++) {
            int t=m[i][j]; m[i][j]=m[j][i]; m[j][i]=t;
        }
    for (int[] row : m) {
        int lo=0, hi=n-1;
        while (lo<hi) { int t=row[lo]; row[lo]=row[hi]; row[hi]=t; lo++; hi--; }
    }
}
TimeO(n²)
SpaceO(1)
💡
Variants: Counter-clockwise = Transpose + reverse each column. 180° = reverse rows + reverse each row.
Problem 03 · In-Place State Machine
Set Matrix Zeroes
MediumAmazonMicrosoftGoldman SachsSentinel Encoding

If any cell is 0, set its entire row and column to 0. Do it in place using O(1) extra space.

Input: [[1,1,1],[1,0,1],[1,1,1]] Output: [[1,0,1],[0,0,0],[1,0,1]]

Naive: use a separate boolean array to mark rows/cols → O(m+n) space. Optimised: borrow the first row and first column as your marker arrays. Two boolean flags remember if those borrowed sentinels themselves originally had zeros. 4 passes total, all O(m*n) time, O(1) space.

Full Solution
☕ Java · O(1) Space Sentinels
void setZeroes(int[][] m) {
    boolean r0=false, c0=false;
    for (int c=0; c<m[0].length; c++) if (m[0][c]==0) r0=true;
    for (int r=0; r<m.length;    r++) if (m[r][0]==0) c0=true;
    for (int r=1; r<m.length; r++)
        for (int c=1; c<m[0].length; c++)
            if (m[r][c]==0) { m[r][0]=0; m[0][c]=0; }
    for (int r=1; r<m.length; r++)
        for (int c=1; c<m[0].length; c++)
            if (m[r][0]==0||m[0][c]==0) m[r][c]=0;
    if (r0) for (int c=0; c<m[0].length; c++) m[0][c]=0;
    if (c0) for (int r=0; r<m.length;    r++) m[r][0]=0;
}
TimeO(m*n)
SpaceO(1)
Problem 04 · Grid DFS / Flood Fill
Number of Islands
MediumAmazonGoogleMetaGrid DFS

Given a 2D grid of '1' (land) and '0' (water), count the number of islands (groups of adjacent land cells).

Input: [['1','1','0','0'], ['1','1','0','0'], ['0','0','1','0'], ['0','0','0','1']] Output: 3

Scan every cell. Each time you find an unvisited '1', you've discovered a new island → increment count. Then DFS to sink the entire island (change all connected '1's to '2' so they are never counted again). This is the Flood Fill pattern — exactly how a paint-bucket tool works.

Full Solution + Dry Run
☕ Java · DFS Flood Fill
int numIslands(char[][] g) {
    int count=0;
    for (int r=0; r<g.length; r++)
        for (int c=0; c<g[0].length; c++)
            if (g[r][c]=='1') { count++; dfs(g,r,c); }
    return count;
}
void dfs(char[][] g, int r, int c) {
    if (r<0||r>=g.length||c<0||c>=g[0].length||g[r][c]!='1') return;
    g[r][c]='2';
    dfs(g,r-1,c); dfs(g,r+1,c); dfs(g,r,c-1); dfs(g,r,c+1);
}
// Islands at (0,0)-(1,1) → count=1, Island (2,2) → count=2, (3,3) → count=3
TimeO(m*n)
SpaceO(m*n)
🔭
Interview follow-up: DFS can stack-overflow on huge grids. Convert to iterative BFS — same O(m*n), zero stack risk.
Problem 05 · Multi-Source BFS
01 Matrix (Distance to Nearest 0)
MediumGoogleAmazonMulti-Source BFS

Given a binary matrix, return a matrix where each cell = distance to its nearest 0.

Input: [[0,0,0],[0,1,0],[1,1,1]] Output: [[0,0,0],[0,1,0],[1,2,1]]

Wrong approach: For every 1-cell, BFS to find nearest 0 → O((m*n)²).
Key insight: Seed BFS with ALL 0-cells simultaneously. BFS radiates outward level-by-level. Each 1-cell gets its distance from whichever 0-source reaches it first — guaranteed to be the nearest. Single O(m*n) pass.

Full Solution + Trace
☕ Java · Multi-Source BFS
int[][] updateMatrix(int[][] mat) {
    int m=mat.length, n=mat[0].length;
    int[][] dist = new int[m][n];
    Queue<int[]> q = new LinkedList<>();
    for (int r=0; r<m; r++) for (int c=0; c<n; c++) {
        if (mat[r][c]==0) { dist[r][c]=0; q.offer(new int[]{r,c}); }
        else dist[r][c]=-1;
    }
    int[][] dirs={{-1,0},{1,0},{0,-1},{0,1}};
    while (!q.isEmpty()) {
        int[] cur=q.poll();
        for (int[] d:dirs) {
            int nr=cur[0]+d[0], nc=cur[1]+d[1];
            if (nr>=0&&nr<m&&nc>=0&&nc<n&&dist[nr][nc]==-1) {
                dist[nr][nc]=dist[cur[0]][cur[1]]+1;
                q.offer(new int[]{nr,nc});
            }
        }
    }
    return dist;
}
TimeO(m*n)
SpaceO(m*n)
Problem 06 · Multi-Source BFS with Time Tracking
Rotting Oranges
MediumAmazonGoogleMulti-Source BFS

Grid cells: 0=empty, 1=fresh orange, 2=rotten. Each minute, rotten oranges spread to adjacent fresh ones. Return minimum minutes to rot all, or -1 if impossible.

Input: [[2,1,1],[1,1,0],[0,1,1]] → Output: 4 Input: [[2,1,1],[0,1,1],[1,0,1]] → Output: -1 (isolated fresh)

Same multi-source BFS as 01 Matrix, but now track BFS levels as minutes. Count fresh oranges upfront. After BFS completes, if fresh > 0 → return -1 (unreachable). Otherwise return minute count.

Full Solution
☕ Java · BFS with Level Tracking
int orangesRotting(int[][] g) {
    int m=g.length, n=g[0].length, fresh=0, mins=0;
    Queue<int[]> q=new LinkedList<>();
    for (int r=0;r<m;r++) for (int c=0;c<n;c++) {
        if (g[r][c]==2) q.offer(new int[]{r,c});
        if (g[r][c]==1) fresh++;
    }
    if (fresh==0) return 0;
    int[][] dirs={{-1,0},{1,0},{0,-1},{0,1}};
    while (!q.isEmpty()&&fresh>0) {
        mins++;
        int sz=q.size();
        for (int i=0;i<sz;i++) {
            int[] cur=q.poll();
            for (int[] d:dirs) {
                int nr=cur[0]+d[0], nc=cur[1]+d[1];
                if (nr>=0&&nr<m&&nc>=0&&nc<n&&g[nr][nc]==1) {
                    g[nr][nc]=2; fresh--; q.offer(new int[]{nr,nc});
                }
            }
        }
    }
    return fresh==0 ? mins : -1;
}
TimeO(m*n)
SpaceO(m*n)
Problem 07 · 2D Binary Search
Search a 2D Matrix II
MediumGoogleMicrosoftCorner Walk O(m+n)

Integers in each row are sorted left-to-right; integers in each column are sorted top-to-bottom. Search for a target in O(m+n).

Matrix: [[1,4,7,11],[2,5,8,12],[3,6,9,16],[10,13,14,17]] target=5 → true | target=20 → false

Start at top-right corner. This is the max of its row and min of its column. If target < current → go left (eliminate this column). If target > current → go down (eliminate this row). Each step eliminates one row or column → O(m+n) total.

Full Solution + Walk Trace
☕ Java · Corner Walk
boolean searchMatrix(int[][] m, int t) {
    int r=0, c=m[0].length-1;
    while (r<m.length && c>=0) {
        if      (m[r][c]==t) return true;
        else if (m[r][c]>t)  c--;
        else               r++;
    }
    return false;
}
// Trace target=5: (0,3)=11>5→c=2, (0,2)=7>5→c=1,
// (0,1)=4<5→r=1, (1,1)=5==5 → true ✓
TimeO(m+n)
SpaceO(1)
LC 74 vs LC 240: LC 74 is fully row-major sorted (treat as 1D → use classic binary search O(log mn)). LC 240 only guarantees row-sorted + col-sorted → must use corner walk.
Problem 08 · Reverse Multi-Source BFS
Pacific Atlantic Water Flow
MediumGoogleAmazonReverse BFS / DFS

Water flows from higher or equal cells to lower. Find all cells that can flow to both Pacific (top/left edges) and Atlantic (bottom/right edges) oceans.

Reverse the flow direction. Instead of asking "where can this cell drain to?", ask "which cells can reach this ocean boundary?". BFS/DFS from Pacific borders going uphill, then BFS/DFS from Atlantic borders going uphill. Cells reachable from BOTH are the answer.

Full Solution
☕ Java · Dual BFS
List<List<Integer>> pacificAtlantic(int[][] h) {
    int m=h.length, n=h[0].length;
    boolean[][] pac=new boolean[m][n], atl=new boolean[m][n];
    Queue<int[]> pq=new LinkedList<>(), aq=new LinkedList<>();
    for (int i=0;i<m;i++) { pq.offer(new int[]{i,0}); pac[i][0]=true;
                              aq.offer(new int[]{i,n-1}); atl[i][n-1]=true; }
    for (int j=0;j<n;j++) { pq.offer(new int[]{0,j}); pac[0][j]=true;
                              aq.offer(new int[]{m-1,j}); atl[m-1][j]=true; }
    bfs(h, pq, pac, m, n); bfs(h, aq, atl, m, n);
    List<List<Integer>> res=new ArrayList<>();
    for (int r=0;r<m;r++) for (int c=0;c<n;c++)
        if (pac[r][c]&&atl[r][c]) res.add(Arrays.asList(r,c));
    return res;
}
void bfs(int[][] h, Queue<int[]> q, boolean[][] vis, int m, int n) {
    int[][] d={{-1,0},{1,0},{0,-1},{0,1}};
    while (!q.isEmpty()) {
        int[] c=q.poll();
        for (int[] dir:d) {
            int nr=c[0]+dir[0], nc=c[1]+dir[1];
            if (nr>=0&&nr<m&&nc>=0&&nc<n&&!vis[nr][nc]&&h[nr][nc]>=h[c[0]][c[1]]) {
                vis[nr][nc]=true; q.offer(new int[]{nr,nc});
            }
        }
    }
}
TimeO(m*n)
SpaceO(m*n)

📝 Assignment — Company Interview Problems

📋
Topic 14 Assignment — 24 Problems (5 Easy · 14 Medium · 5 Hard)
All 4 matrix patterns covered. Problems sorted by company frequency and difficulty. Each problem in the assignment file includes: the LeetCode link, the exact pattern to apply, a step-by-step hint, common mistakes, and the companies that ask it most frequently.

📄 Open Assignment.md →
5
🟩 Easy
Flood Fill · Island Perimeter · Diagonal Sum · Search Matrix I · Count Negatives
14
🟨 Medium
Spiral · Rotate · Islands · BFS · Pacific Atlantic · Word Search · and 8 more
5
🟥 Hard
Shortest Path · Walls & Gates · Rain Water II · Min Path · Word Search II

✅ Lecture Completion Checklist

Check each item before advancing to Lecture 15 (Trees). Be honest — these are your interview readiness criteria.

I can write the spiral matrix 4-pointer loop from memory, including the two guards
I can explain why Rotate Image = Transpose + Reverse, and derive counter-clockwise variant
I can solve Set Matrix Zeroes in O(1) space using the first row and column as sentinels
I can implement grid DFS flood fill and explain when to use BFS vs DFS on a grid
I understand multi-source BFS and why seeding ALL sources first gives O(m*n) not O((m*n)²)
I can explain the top-right corner walk for Search 2D Matrix II and why O(m+n) works
I know the difference: LC 74 (fully sorted → binary search) vs LC 240 (row+col sorted → corner walk)
I can identify which of the 4 patterns applies within 30 seconds of reading any matrix problem
I have completed all 24 assignment problems and can explain the pattern behind each one
🌳
You are ready for Topic 15: Trees (Binary Trees & BST)
Trees are the natural progression from 2D grids — both are graphs you traverse with DFS and BFS. Pre/in/post-order traversal = DFS patterns. Level-order = BFS. The grid patterns you just mastered will reappear constantly in tree problems. You are building on solid ground.
← Topic 13: HashMap & HashSet Topic 14 of 30 — Phase 2 Core Data Structures Topic 15: Trees →