Matrices & Simulation
A grid is an array with two indices. Master the index maths, then rotate, spiral and simulate it in place.
▶ guided lesson⚡ 1-minute summary↻ 14 recall cards
before this: Arrays & Strings · Java Arrays & Strings
01 · why it exists
Why this exists, and the weight it carries
since1957 · 1972
Row-major layout & index maths
John Backus's IBM FORTRAN team (column order); Dennis Ritchie at Bell Labs (C, row order)
A grid has rows and columns, but memory is one long line of numbered slots. Every language must decide which cell comes next.
FORTRAN (IBM, 1957) chose columns: the 1957 paper's address formula for A(I, J, K) multiplies J by the size of the first dimension, so the first subscript moves fastest.
C, which grew up at Bell Labs between 1969 and 1973, chose rows: the C standard says arrays are stored in row-major order, the last subscript varying fastest.
Java (1996) made int[][] an array of references to row arrays (JLS chapter 10). Each row is its own int[], so walking along a row is the fast direction.
the problem it solvedTurning a two-dimensional table into addresses in one-dimensional memory, with one multiply and one add per lookup.
its jobs today
- Images: Java's
BufferedImage.getRGBreturns pixels in oneint[], pixel (x, y) aty × scansize + x(with zero offsets). - Grid problems turn a cell into one
intid,r * cols + c, for visited arrays, union-find and hash sets. - Numeric libraries such as NumPy let you pick row-major ('C') or column-major ('F') order, because the two styles meet in real code.
the weight it carries
Illustrative: a 1920 × 1080 screenshot = 20,73,600 pixels. Pixel (x = 100, y = 500) sits at 500 × 1920 + 100 = 9,60,100: one multiply, one add. Assume 64-byte cache lines, so 16 ints per line: a row-by-row walk then misses about once per 16 pixels: 20,73,600 / 16 = 1,29,600 misses. A column-by-column walk over a big image can miss on almost every pixel.
without it
Every grid would need its own map from (row, col) to memory, and image buffers, flat visited arrays and cell ids like r * cols + c would all be ad hoc.
when · why · how
- when
- You need one number per cell (visited, union-find, a set key), a flat buffer, or you walk a large grid.
- why
- O(1) both ways:
i = r·cols + c,r = i / cols,c = i % cols. Row-order loops follow memory order, which caches love. - how
int id = r * cols + c;back withid / colsandid % cols. Looproutside andcinside. Switch tolongpast about 2.1 × 10⁹ cells.
since?
Direction arrays & boundary walks
Storing grid moves as {dr, dc} pairs, and walking a spiral with four shrinking walls, are programming folklore from games and puzzles. We found no documented inventor.
its jobs today
- Games: Minesweeper's numbers are counts over the 8 neighbours; a snake game can turn right with
(d + 1) % 4. - Image filters such as blur and edge detection read a small neighbourhood (often 3 × 3) around every pixel.
- Grid BFS and DFS (the Graphs chapter) generate a cell's neighbours on the fly instead of storing edges.
the weight it carries
Illustrative: a 1000 × 1000 Game of Life board. One generation = 10,00,000 cells × 8 neighbours = 80,00,000 neighbour checks, all through one DIRS loop and one bounds check instead of 8 hand-written copies.
without it
Eight copy-pasted if blocks per cell. Each new move set (diagonals, knight moves) means another copy, and one wrong sign silently breaks the walk.
when · why · how
- when
- Any "look at the neighbours" or "walk and turn" grid task: spiral order, flood fill, Game of Life, robot moves.
- why
- The same O(1) work per neighbour, written once. Turning becomes index arithmetic, and the four-wall spiral needs O(1) extra space instead of a visited grid.
- how
int[][] DIRS = {{-1,0},{0,1},{1,0},{0,-1}};thenfor (int[] d : DIRS) { int nr = r + d[0], nc = c + d[1]; if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) … }.
since?
Rotation by transpose + reverse
The transpose is basic linear algebra. Doing a quarter turn as "transpose, then mirror each row" is programming folklore; we found no documented first use.
its jobs today
- Photo and phone-gallery apps rotate pictures by 90°: clockwise, every pixel (r, c) moves to (c, n − 1 − r) for a square image.
- Puzzle games can rotate a piece kept in a small square grid (like a Tetris block) the same way.
the weight it carries
Illustrative: a 1000 × 1000 int tile. Copy-rotate needs a second 10,00,000-cell buffer (about 4 MB). Transpose + reverse makes 1000 × 999 / 2 = 4,99,500 transpose swaps plus 1000 × 500 = 5,00,000 reverse swaps: 9,99,500 swaps in all, with one temp variable.
without it
Every rotation would need a second full-size buffer, or the four-way cycle swap, which is easy to get wrong under pressure.
when · why · how
- when
- Rotate or flip a square matrix in place.
- why
- O(n²) time, since each cell moves a constant number of times, and O(1) extra space versus O(n²) for a copy.
- how
- Transpose with
cstarting atr + 1, then reverse each row with two pointers. Counter-clockwise: reverse each row first, then transpose.
since?
In-place markers (row 0 / column 0, spare bits)
Reusing part of the input as scratch space is an old space-saving habit with no single inventor. Set Matrix Zeroes and Game of Life are its best-known interview forms.
its jobs today
- Memory-tight grid updates, where a second m × n buffer costs too much.
- Packing several yes/no facts into one int with bit flags, like the read/write/execute permission bits on a file.
the weight it carries
Illustrative: a 1000 × 1000 int matrix is 40,00,000 bytes (about 4 MB). A full copy costs another 4 MB. Row and column flags cost 1000 + 1000 booleans (about 2 KB). Row 0 / column 0 markers cost two booleans.
without it
Set Matrix Zeroes and Game of Life would need O(m·n) or O(m + n) extra memory, or you'd overwrite facts you still need (a zero you wrote looks like an original zero).
when · why · how
- when
- "In place" or "O(1) extra space" on a grid, when a cell's update depends on values you are about to overwrite.
- why
- Same O(m·n) time; extra space drops from O(m·n) to O(1). The price is careful ordering: save the marker row/column's own state first, apply it last.
- how
- Set Zeroes:
matrix[r][0] = 0; matrix[0][c] = 0;plus two booleans. Game of Life:board[r][c] |= 2for "alive next", read with& 1, finish with>>= 1.
since1948 · 1970
Cellular automata & generation updates
John von Neumann and Stanislaw Ulam; John Horton Conway; popularised by Martin Gardner
In 1948 John von Neumann set out to describe a machine that could build a copy of itself. His colleague Stanislaw Ulam suggested a simpler world: a grid of cells, each in one of a fixed set of states, all updating together by one local rule. Von Neumann's design used 29 states per cell. He died in 1957; Arthur Burks completed and published the work in 1966 as Theory of Self-Reproducing Automata. In 1970 John Conway introduced Life, with just two states and the birth-on-3, survive-on-2-or-3 rule. Martin Gardner's October 1970 Scientific American column brought it to a wide audience.
the problem it solvedA precise model of many simple parts, one local rule and one shared clock, for studying how complex behaviour grows from simple rules.
its jobs today
- Grid simulations where every cell updates from its neighbours at the same moment, such as Life programs and other cellular-automaton models.
- Image filters read the old image and write a new one, the same old-versus-new rule.
- Games and video use double buffering: draw the next frame off-screen while the current one is shown.
the weight it carries
Illustrative: a 1000 × 1000 board. One generation = 10,00,000 cells × 8 = 80,00,000 neighbour checks. The copy version also allocates a second 10,00,000-cell board (about 4 MB as int) every generation. The 2-bit version needs none.
without it
Update cells one at a time on a single board, and later cells see half-updated neighbours: the generation is wrong, and patterns like the glider fall apart.
when · why · how
- when
- "All cells change at the same time": each new state depends only on the old states around it.
- why
- Read only from generation t, write only to t + 1. A copy costs O(m·n) extra space; 2-bit encoding costs O(1). Both take O(m·n) time with 8 checks per cell.
- how
- Copy:
old[r] = board[r].clone(). In place:live += board[nr][nc] & 1, thenboard[r][c] |= 2when it lives, thenboard[r][c] >>= 1for every cell.
02 · plain english
The idea in 30 seconds
A matrix looks like a grid, but memory is one long line. So every grid is stored row after row, and cell (r, c) is number r × cols + c on that line.
With that index maths and a small table of directions, you can walk a grid in any order: rows, rings, diagonals, zigzags, neighbours.
Most grid questions are careful simulations: change the cells in place without destroying information you still need.
picture this
Your laptop screen. 1920 × 1080 pixels look like a grid, but the image sits in RAM as one long run of numbers, line after line. Java's BufferedImage.getRGB hands pixels back in one int[], with pixel (x, y) at index y × scansize + x (with its offsets at 0): row y first, then column x. Rotate a photo, blur it, or count Minesweeper neighbours, and you are doing this chapter's index maths.
03 · remember
What you must know
- Row-major: cell (r, c) is index
r * cols + cof one long line. The way back isr = i / cols,c = i % cols. Always divide by cols, never by rows. - Java's `int[][]` is an array of row arrays. Each row is its own
int[]. Looproutside andcinside, so you read each row in memory order. - Direction arrays: keep moves in a table like
{{-1,0},{0,1},{1,0},{0,-1}}(clockwise). Turning right is(d + 1) % 4. Check the bounds before you read a neighbour. - Layer by layer: four walls (top, bottom, left, right). Walk one side, push that wall inwards, and stop when the walls cross.
- Rotation = two mirrors: a clockwise quarter turn sends (r, c) to (c, n − 1 − r). Transpose, then reverse every row. O(1) extra space.
- Mark first, write later: when one cell's change affects a whole row or column, record what must happen, then do it. Row 0 and column 0 can be the notebook.
- Two states in one cell: bit 0 = the value now, bit 1 = the value next. Read
& 1, plan with|= 2, finish with>>= 1. - Simulation discipline: read only from the old state, write only to the new one. Mixing them is the classic Game of Life bug.
- Rectangles, not squares: test 1 × 1, 1 × n, n × 1 and 3 × 4. Most grid bugs hide in a single leftover row or column.
04 · see it
Play with it in 3D
Press Space to play, ←/→ to step, drag to move, ? for all shortcuts. Try your own input.
Row-major: one grid, one long line
Each row becomes one unbroken run of the flat array. (r, c) lands at r × cols + c, and i / cols, i % cols takes you back.
Spiral order with four shrinking walls
Walk a side, push that wall in. The two guards stop a single leftover row or column from being walked twice.
Rotate 90°: transpose, then reverse each row
The transpose turns rows into columns. Reversing each row finishes the clockwise turn.
Row 0 and column 0 as a notebook
Phase 1 writes the marks, phase 2 obeys them. Row 0 and column 0 are cleared last, so no mark is lost early.
Game of Life generations, in place
Bit 0 is now, bit 1 is next. No cell's 'now' bit changes until every cell has been decided.
05 · cost
Time & space, explained
| Time | Extra space | why | |
|---|---|---|---|
Read or write grid[r][c] | O(1) | O(1) | Two index steps: find row r's array, then slot c in it. |
Flat index r * cols + c and back | O(1) | O(1) | One multiply and one add; back is one divide and one remainder. |
| Visit every cell (rows, spiral, diagonals, zigzag) | O(m·n) | O(1) | Each cell is visited once. Only the order changes. |
| Check all 8 neighbours of every cell | O(m·n) | O(1) | 8 constant-time checks per cell: 8·m·n steps. |
| Transpose m × n into a new n × m | O(m·n) | O(m·n) | The shape changes, so a new matrix is unavoidable. |
| Transpose a square matrix in place | O(n²) | O(1) | n(n − 1)/2 swaps above the diagonal, one temp variable. |
| Deep-copy a grid | O(m·n) | O(m·n) | Every row is cloned. |
| Time | Extra space | why | |
|---|---|---|---|
| Set Zeroes: copy, then wipe rows and columns | O(m·n·(m + n)) | O(m·n) | Each original 0 wipes m + n cells; the copy is a full second matrix. |
| Set Zeroes: row and column flags | O(m·n) | O(m + n) | Two passes; one boolean per row and per column. |
| Set Zeroes: row 0 and column 0 as markers | O(m·n) | O(1) | Same two passes; the marks live inside the matrix, plus two booleans. |
| Game of Life: copy the board | O(m·n) | O(m·n) | 8 checks per cell, reading from a frozen copy. |
| Game of Life: two bits per cell | O(m·n) | O(1) | The same checks; the next state hides in bit 1 until a final shift. |
| Rotate: copy vs transpose + reverse | O(n²) | O(n²) vs O(1) | Both move every cell a constant number of times; only the copy needs a second matrix. |
| Spiral: visited grid vs four walls | O(m·n) | O(m·n) vs O(1) | Both visit each cell once; the walls replace the visited grid. |
| Zigzag: draw a grid / row builders / cycle jumps | O(rows·n) / O(n) / O(n) | O(rows·n) / O(n) / O(1) | The grid has rows × n cells to scan; builders hold n chars; jumps compute every position (besides the output). |
06 · java
Raw vs Collections Framework
Row-major index maths
class RowMajor { /** Copies an m x n grid into one int[], row by row: cell (r, c) lands at index r * cols + c. */ static int[] flatten(int[][] grid) { int rows = grid.length, cols = grid[0].length; int[] flat = new int[rows * cols]; for (int r = 0; r < rows; r++) { // row r starts at index r * cols for (int c = 0; c < cols; c++) { flat[r * cols + c] = grid[r][c]; } } return flat; } /** The way back: index i is in row i / cols and column i % cols. Divide by cols, not rows. */ static int[] cellOf(int i, int cols) { return new int[] {i / cols, i % cols}; }}grid.lengthis the number of rows;grid[0].lengthis the number of columns (for a rectangle).r * cols + cturns a cell into oneint. That's handy as avisitedindex, a union-find id or aHashSet<Integer>key, instead of anint[]pair.- The way back divides by cols: index 6 in a 4-column grid is row 6 / 4 = 1, column 6 % 4 = 2.
- For a big grid,
r * cols + ccan overflowintonce rows × cols passes about 2.1 × 10⁹. Uselongthen.
Direction arrays
class Directions { // Clockwise from "up": turning right is d + 1, turning back is d + 2 (both % 4). static final int[][] DIRS4 = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; static final int[][] DIRS8 = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; /** How many of the 8 cells around (r, c) hold a 1. Cells outside the grid don't exist. */ static int liveNeighbours(int[][] grid, int r, int c) { int count = 0; for (int[] d : DIRS8) { int nr = r + d[0], nc = c + d[1]; if (nr >= 0 && nr < grid.length && nc >= 0 && nc < grid[0].length) count += grid[nr][nc]; } return count; } static int turnRight(int d) { return (d + 1) % 4; }}- Store moves as
{dr, dc}pairs. One loop plus one bounds check replaces 4 or 8 copy-pastedifblocks. - Keep the 4 directions in clockwise order. Then turning right is
(d + 1) % 4and turning around is(d + 2) % 4. - Check
nr >= 0 && nr < rows && nc >= 0 && nc < colsbeforegrid[nr][nc]. The&&stops early, so the read never runs out of bounds.
Diagonals by index
class Diagonals { /** Sum of the "\" diagonal through (r, c): every cell on it has the same r - c. */ static int diagonalSum(int[][] grid, int r, int c) { int sum = 0; for (int i = 0; i < grid.length; i++) for (int j = 0; j < grid[0].length; j++) if (i - j == r - c) sum += grid[i][j]; return sum; } /** Cells grouped by anti-diagonal ("/"): r + c runs from 0 to rows + cols - 2. */ static List<List<Integer>> antiDiagonals(int[][] grid) { int rows = grid.length, cols = grid[0].length; List<List<Integer>> out = new ArrayList<>(); for (int k = 0; k <= rows + cols - 2; k++) out.add(new ArrayList<>()); for (int r = 0; r < rows; r++) for (int c = 0; c < cols; c++) out.get(r + c).add(grid[r][c]); return out; }}- Along a ↘ diagonal,
r - cstays the same. Along a ↙ anti-diagonal,r + cstays the same. r + cruns from 0 to rows + cols − 2.r - ccan be negative, so addcols - 1before using it as an array index.- N-Queens uses exactly this: one boolean per
r + cand one perr - ctells you if a diagonal is already attacked.
Transpose: a new matrix or in place
class Transpose { /** m x n becomes n x m. The shape changes, so it needs a new matrix. */ static int[][] transpose(int[][] m) { int rows = m.length, cols = m[0].length; int[][] t = new int[cols][rows]; for (int r = 0; r < rows; r++) for (int c = 0; c < cols; c++) t[c][r] = m[r][c]; return t; } /** Square only: swap across the main diagonal, each pair once (c starts at r + 1). */ static void transposeInPlace(int[][] m) { for (int r = 0; r < m.length; r++) for (int c = r + 1; c < m.length; c++) { int tmp = m[r][c]; m[r][c] = m[c][r]; m[c][r] = tmp; } }}- A rectangle changes shape when transposed (3 × 4 → 4 × 3), so it needs a new matrix.
- A square can be transposed in place. Start
catr + 1: starting at 0 swaps every pair twice and changes nothing. - Transpose + reverse each row = rotate clockwise. Transpose + reverse each column = rotate counter-clockwise.
Copying a grid
class CopyGrid { /** A real copy: clone every row. grid.clone() alone copies only the outer array of row references. */ static int[][] deepCopy(int[][] grid) { int[][] copy = new int[grid.length][]; for (int r = 0; r < grid.length; r++) copy[r] = grid[r].clone(); return copy; }}class CopyGridStreams { static int[][] deepCopy(int[][] grid) { return Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new); }}grid.clone()is shallow: the JLS (§10.7) says the subarrays are shared. Changingcopy[0][0]would changegrid[0][0]too.- Clone each row:
copy[r] = grid[r].clone(). The stream version does the same withmap(int[]::clone). - Print a grid with
Arrays.deepToString(grid)and compare two grids withArrays.deepEquals(a, b).
Two states in one cell
class TwoStates { // One int, two facts: bit 0 = the value now, bit 1 = the value in the next round. static int now(int cell) { return cell & 1; } static int withNext(int cell, int next) { return cell | (next << 1); } static int advance(int cell) { return cell >> 1; // the next value becomes the current one }}- When cells hold only 0 or 1, the higher bits are free. Bit 1 can carry the next state without touching bit 0.
- Neighbours read
cell & 1, so they still see the old generation while you plan the new one. cell >> 1moves the plan into place. The same idea works with any small encoding, like 2 = 'was dead, now alive'.
| call | does | cost |
|---|---|---|
new int[rows][cols] | A rows × cols grid of 0s (one int[] per row) | O(rows·cols) |
grid.length / grid[0].length | Number of rows / columns | O(1) |
grid[r].clone() | Copy one row | O(cols) |
Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new) | Deep copy in one line | O(rows·cols) |
Arrays.fill(grid[r], 0) | Set a whole row to one value | O(cols) |
Arrays.deepToString(grid) / Arrays.deepEquals(a, b) | Print / compare 2D contents | O(rows·cols) |
x & 1 / x | 2 / x >> 1 | Read bit 0 / set bit 1 / shift bit 1 into bit 0 | O(1) |
new StringBuilder[k] | k slots that start as null: create each builder before use | O(k) |
One number per cell (visited, union-find, set key)
→ r * cols + c
A single int instead of an int[] pair or a String key; O(1) both ways.
Look at neighbours, or walk and turn
→ A DIRS array + one bounds check
One loop for 4 or 8 directions; turning is (d + 1) % 4.
Spiral or ring order
→ Four walls: top, bottom, left, right
O(1) extra space instead of a visited grid.
Rotate or flip a square in place
→ Transpose + reverse
Two easy loops, one temp variable.
New state depends on old neighbours
→ A copy (simple) or bits in the cell (O(1) space)
Readers must keep seeing the old generation.
Mark rows or columns for later
→ boolean[] rows, cols, or row 0 / column 0 of the matrix
O(m + n) and clear, or O(1) with careful ordering.
07 · recognise
Spot the pattern
"Spiral order", "layer by layer", "ring"
Four shrinking walls, with guards for a single leftover row or column
"Rotate the image 90°" in place, n × n
Transpose, then reverse every row
"If a cell is 0, set its whole row and column to 0"
Mark first, write later; row 0 and column 0 as markers
"All cells update at the same time", "next generation", "next state"
Read old, write new: a copy, or two bits per cell
"Write it in a zigzag", "rails", "up and down the rows"
One builder per row with a direction that flips, or a cycle of 2·rows − 2
"Neighbours", "adjacent", "8 directions"
A DIRS array with one bounds check
"The k-th cell", "treat the matrix as one sorted list"
Flat index: i = r·cols + c, back with i / cols and i % cols
"Diagonal", "anti-diagonal"
r − c is fixed on ↘, r + c is fixed on ↙
08 · traps & tricks
Mistakes to avoid, tricks to use
traps
- Un-flattening with
i / rowsinstead ofi / cols. It only works by luck on square grids. grid.clone()copies only the outer array. The rows are shared, so your "copy" changes the original.- Updating a cell while other cells still need its old value (Game of Life, Set Matrix Zeroes). Freeze a copy or encode old + new.
- Zeroing row 0 or column 0 before the inner cells have used them as markers. Markers go last.
- Transposing with
cstarting at 0: every pair is swapped twice, and nothing changes. - Spiral without the
top <= bottom/left <= rightguards: a single leftover row is walked forwards and then backwards. - Marking cells with a "special" value like −1 or
Integer.MIN_VALUEwhen everyintis a legal cell value. new StringBuilder[k]gives k nulls, not k builders. Callingappendon one throwsNullPointerException.- Mixing up (x, y) and (r, c). x is the column and y is the row, so pixel (x, y) is
grid[y][x].
tricks
- Before any transform, write the mapping: (r, c) → (?, ?). Rotation, transpose and flips all follow from it.
- Draw a 3 × 4 rectangle, not a square. Then test 1 × 1, 1 × n and n × 1 before you say "done".
- For simulations, say out loud: "I read from the old state and write to the new one." Interviewers listen for that sentence.
- Name your bounds once:
int rows = grid.length, cols = grid[0].length;. Fewer chances to mix them up later. - Chalo, dry-run karte hain: take a 3 × 3 on paper, write the variables as columns, and fill one line per step. Grid bugs show up by the third line.
09 · why & how
Questions you might be too shy to ask
Is Java's int[][] stored row by row, like in C?
Almost. In C, a 2D array is one block, row after row. In Java, int[][] is an array of references to row arrays (JLS chapter 10). Each row is its own int[], but the rows can sit anywhere in the heap. Reading along a row is still the fast direction. Need one truly continuous block? Use a flat int[rows * cols] with r * cols + c.
Why does i / cols give the row?
Every row holds exactly cols cells. So the first cols indices are row 0, the next cols are row 1, and so on. Dividing by cols counts how many full rows come before index i. The remainder i % cols is how far into that row you are.
Why is "up" written as {-1, 0}? In maths, up is +1.
In a grid, row 0 is at the top and row numbers grow as you go down, like lines in a file or pixels on a screen.
So moving up means going to a smaller row: r - 1. Moving down is r + 1, left is c - 1, right is c + 1.
That's why {{-1,0},{0,1},{1,0},{0,-1}} reads up, right, down, left: clockwise.
Rotate Image: how do I work out (r, c) → (c, n − 1 − r) myself instead of memorising it?
Watch one row. After a clockwise turn, the top row becomes the right column, and row 1 becomes the column just left of it.
So old row r lands in column n − 1 − r.
Along that row, left-to-right becomes top-to-bottom, so old column c becomes row c.
Check on the 3 × 3 example: 7 sits at (2, 0) and moves to (0, 0) — the top-left of [[7,4,1],…].
How do I rotate counter-clockwise, or by 180°?
Counter-clockwise: transpose, then reverse each column (or reverse each row first, then transpose). 180°: reverse the order of the rows, then reverse each row. Or rotate clockwise twice. Write the mapping first: 180° sends (r, c) to (n − 1 − r, n − 1 − c).
Spiral Matrix: why is the loop top <= bottom, with <=, and not top < bottom?
When top == bottom, one row is still left to print.
Take [[1, 2, 3]]: top = 0 and bottom = 0 at the start. With <, the loop never runs and you return an empty list.
The walls are inclusive — both top and bottom are rows you still have to print. Same for left and right.
Spiral Matrix: why don't the corner cells get printed twice?
Each corner belongs to exactly one side, because a wall moves right after its side is walked.
The top row prints both top corners, then top++. So the right column starts one row lower and skips the top-right corner.
Then right--, so the bottom row skips the bottom-right corner. Then bottom--, so the left column skips the bottom-left one.
Dry-run a 3 × 3 once with the sim and watch the four walls move. Simple hai.
Zigzag Conversion: why is one cycle 2 * numRows - 2 characters and not 2 * numRows?
The top and bottom rows are visited only once per trip; the middle rows are visited twice. With numRows = 4, going down covers rows 0, 1, 2, 3 (4 characters). Coming back up covers only rows 2 and 1 (2 characters), because row 3 and row 0 belong to the next trip. That's 4 + 2 = 6 = 2 · 4 − 2. Row 0 then takes indices 0, 6, 12, …
Does the output list count as extra space in Spiral Matrix or Zigzag?
No. By the usual interview convention, the space you must return doesn't count. Say it out loud: "O(1) extra space besides the output."
Set Matrix Zeroes: why can't I zero a row as soon as I find a 0?
Because the zeros you write look exactly like original zeros. When the scan reaches them, it wipes more rows and columns that should have stayed. Record which rows and columns must go first, then write.
Why is it safe to write the markers into row 0 and column 0?
A mark in matrix[r][0] means row r will become all zeros, so that cell was going to be 0 anyway. The same holds for matrix[0][c]. The only facts you'd lose are row 0's and column 0's own zeros, so you save those in two booleans before marking.
Game of Life: why not update each cell in one pass?
Every cell must change at the same moment. If you update (0, 0) first, then (0, 1) counts the new (0, 0) instead of the old one, and the generation comes out wrong. Keep the old state readable: a copy, or the old state in bit 0.
Game of Life: I've never used & 1, |= 2 and >>= 1. What are they actually doing?
Think of each cell as a two-digit binary number: the right digit is now, the left digit is next. So 0 = 00, 1 = 01, 2 = 10, 3 = 11.
cell & 1 reads only the right digit (now). That's why a cell holding 2 (born next) still counts as dead for its neighbours: 2 & 1 = 0.
cell |= 2 sets the left digit to 1 ("alive next") without touching the right one.
cell >>= 1 drops the right digit, so next becomes now: 3 → 1, 2 → 1, 1 → 0, 0 → 0.
In the interview, can I just use a copy instead of the in-place trick?
Read the problem first. Rotate Image says "do not allocate another matrix", so a copy breaks the rule there. Set Matrix Zeroes asks for in place, and its follow-up asks for O(1) space: the row and column flags (O(m + n)) are a good first answer. In Game of Life, solving it in place is the follow-up, so a copy first is fine. Say the cost out loud. Then offer the in-place version: "I can drop the extra space by keeping the marks inside the matrix." A working simple answer beats a half-written clever one.
10 · practice
Interview problems
Every problem has brute → better → optimal solutions in Java, with complexity and a dry run.
- #48
- #54
- #6Zigzag ConversionMediumPayPalWalmartAmazonGoogleMicrosoft
- #73
- #289
Also practise this here
Each problem has one home page in the course; these use this chapter's idea too. The note says what to look for.
- #1672Richest Customer WealthEasyin Java Arrays & Strings
A warm-up: walk each row of an
int[][]and keep the best row sum. - #74Search a 2D MatrixMediumin Binary Search
Read row by row, the matrix is one sorted list: binary search over i = 0 … m·n − 1 and turn i into (i / cols, i % cols).
- #36
- #304Range Sum Query 2D - ImmutableMediumin Hashing
Precompute a 2D prefix-sum grid so any rectangle sum is O(1).
- #200
- #51
11 · revise
The whole chapter on one screen
9 cards, about a minute. Read them the night before an interview, or right after the chapter to lock it in.
- what it is
A matrix is rows of equal arrays. Row-major: (r, c) is cell
r * cols + cof one long line; back withi / colsandi % cols. - use it when
Spiral → four walls. Rotate → transpose + reverse. Row/column wipes → markers. "All cells at once" → old vs new. Zigzag → row builders.
- template
Neighbours:
for (int[] d : DIRS) { int nr = r + d[0], nc = c + d[1]; if (nr >= 0 && nr < m && nc >= 0 && nc < n) … } - template
Two states in a cell: read
cell & 1, plancell |= 2, thencell >>= 1. Markers:matrix[r][0] = 0; matrix[0][c] = 0; - cost
Every walk here is O(m·n) time. Only the space differs: a copy O(m·n) → flags O(m + n) → markers or spare bits O(1).
- trap
Writing cells while you still read their old values breaks Game of Life and Set Zeroes. Freeze a copy, or keep old + new in one cell.
- trap
grid.clone()shares rows.i / rowsinstead ofi / cols. Transposing withcfrom 0 swaps each pair twice. - trap
Spiral: without the
top <= bottomandleft <= rightguards, a single leftover row or column is walked twice. - pro tip
Draw a 3 × 4 rectangle, not a square. Then test 1 × 1, 1 × n and n × 1 before you say done.
12 · recall
Flip, remember, repeat
Cell (r, c) of an m × n grid, row-major: its flat index? And the way back?
Question 1: Cell (r, c) of an m × n grid, row-major: its flat index? And the way back?
13 · check yourself
Quick quiz
In a 3 × 5 grid stored row-major, which cell is at index 11?
`int[][] b = a.clone(); b[0][0] = 9;` What happens to `a[0][0]`?
Rotating an n × n matrix 90° clockwise in place can be done by…
Spiral order on [[1, 2, 3]] with the four-wall loop but WITHOUT the two inner guards returns…
Set Matrix Zeroes with row 0 and column 0 as markers needs how much extra memory?
Game of Life with two bits per cell: after pass 1 a cell holds 2. What does that mean?
Zigzag Conversion with numRows = 4: which indices of s land in row 0?
14 · learn more
A second teacher, if you want one
- ▶ videoSpiral Traversal of a Matrix | Spiral Matrix ↗Striver (take U forward) · EnglishSpiral order with four shrinking boundaries. The dry run settles the off-by-one corners for good.
- ▶ videoLecture 34: Rotate and Spiral Print a Matrix || DSA Series by Babbar ↗Love Babbar (CodeHelp) · HindiRotate by 90° and spiral print, in Hindi with Java code. These two matrix walks keep coming back in interviews.
- ▶ videoSet Matrix Zeroes | O(1) Space Approach | Brute - Better - Optimal ↗Striver (take U forward) · EnglishGoes from extra arrays to O(1) space by using the first row and column as markers. You'll reuse this in-place trick often.