Overview
A matrix (2D grid) is an array of rows, where grid[r][c] is row r, column c. Matrix problems test whether you can move around a grid safely: in 4 or 8 directions, in spiral or diagonal order, and without stepping outside the boundaries.
Most grid problems combine a small set of techniques: a directions array for neighbors, bounds checks, marking visited cells, and layer-by-layer processing for spirals and rotations. Grids are also implicit graphs, where each cell is a node connected to its neighbors.
Each intersection is a cell. From any intersection you can walk north, south, east, or west, unless you are at the city edge. Spiral traversal is walking the outer ring road, then the next ring inward, until you reach the center.
When to use it
- Input is a 2D board, image, map, or game grid.
- The problem asks for spiral order, rotation, transpose, or diagonal traversal.
- You need to explore regions: islands, flood fill, shortest path in a maze.
- The matrix is sorted by rows and columns (staircase search).
Problem patterns it solves
Recognize it when: move up, down, left, right (or 8 directions) from each cell.
- 200. Number of Islands
- 733. Flood Fill
- 463. Island Perimeter
Recognize it when: spiral order, rotate layers, generate a spiral matrix.
- 54. Spiral Matrix
- 59. Spiral Matrix II
- 48. Rotate Image
Recognize it when: rotate 90 degrees in place, flip, transpose.
- 48. Rotate Image
- 867. Transpose Matrix
- 832. Flipping an Image
Recognize it when: cells with the same r - c (or r + c) are on the same diagonal.
- 498. Diagonal Traverse
- 1329. Sort the Matrix Diagonally
- 766. Toeplitz Matrix
Recognize it when: rows and columns are sorted; start from the top-right corner.
- 240. Search a 2D Matrix II
- 74. Search a 2D Matrix
- 1351. Count Negative Numbers in a Sorted Matrix
Recognize it when: use the first row / column or special values to store state in O(1) space.
- 73. Set Matrix Zeroes
- 289. Game of Life
Where it is used in real software
Images are grids of pixels. Blur, sharpen, and edge detection apply a small kernel to each pixel's neighbors; the paint bucket tool is flood fill.
Tile-based games, minesweeper, and chess engines move pieces using direction arrays and bounds checks.
Excel ranges, formulas that reference neighboring cells, and fill-down operations are grid traversals.
Occupancy grids represent free and blocked space for path planning robots in warehouses.
Key terms
- Row-major order
- Rows are stored one after another; iterating row by row is the cache-friendly order.
- Directions array
- [[1,0],[-1,0],[0,1],[0,-1]] lists row and column offsets for 4-directional neighbors.
- Bounds check
- 0 <= r < rows and 0 <= c < cols before reading grid[r][c].
- Visited marking
- Change the cell value or keep a boolean grid so each cell is processed once.
- Flattened index
- Map (r, c) to id = r * cols + c, useful for Union Find or visited sets.
Spiral traversal with four boundaries
- 1Set boundaries
top = 0, bottom = rows - 1, left = 0, right = cols - 1.
- 2Walk the top row left to right
Visit grid[top][left..right], then top++.
- 3Walk the right column top to bottom
Visit grid[top..bottom][right], then right--.
- 4Walk the bottom row right to left
Only if top <= bottom. Visit grid[bottom][right..left], then bottom--.
- 5Walk the left column bottom to top
Only if left <= right. Visit grid[bottom..top][left], then left++. Repeat while top <= bottom and left <= right.
Spiral order of a 3 x 4 matrix
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
| Move | Cells visited | Boundaries after |
|---|---|---|
| Top row, left to right | 1, 2, 3, 4 | top = 1 |
| Right column, down | 8, 12 | right = 2 |
| Bottom row, right to left | 11, 10, 9 | bottom = 1 |
| Left column, up | 5 | left = 1 |
| Top row (inner), left to right | 6, 7 | top = 2 > bottom: stop |
NOWMove: Top row, left to right | Cells visited: 1, 2, 3, 4 | Boundaries after: top = 1
Result: [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]. The two guard checks prevent revisiting the last row or column in non-square matrices.
Implementation
const DIRS = [[1, 0], [-1, 0], [0, 1], [0, -1]]; // Visit valid 4-directional neighborsfunction neighbors(grid, r, c) { const result = []; for (const [dr, dc] of DIRS) { const nr = r + dr, nc = c + dc; if (nr >= 0 && nr < grid.length && nc >= 0 && nc < grid[0].length) { result.push([nr, nc]); } } return result;} function spiralOrder(matrix) { const result = []; let top = 0, bottom = matrix.length - 1; let left = 0, right = matrix[0].length - 1; while (top <= bottom && left <= right) { for (let c = left; c <= right; c++) result.push(matrix[top][c]); top++; for (let r = top; r <= bottom; r++) result.push(matrix[r][right]); right--; if (top <= bottom) { for (let c = right; c >= left; c--) result.push(matrix[bottom][c]); bottom--; } if (left <= right) { for (let r = bottom; r >= top; r--) result.push(matrix[r][left]); left++; } } return result;} // Rotate 90 degrees clockwise in place: transpose, then reverse each rowfunction rotate(matrix) { const n = matrix.length; for (let r = 0; r < n; r++) { for (let c = r + 1; c < n; c++) { [matrix[r][c], matrix[c][r]] = [matrix[c][r], matrix[r][c]]; } } for (const row of matrix) row.reverse();}Complexity and performance
Every cell visited once.
O(1) extra space for in-place rotation.
Each step removes a row or a column.
Worst-case recursion depth on a snake-shaped region.
Trade-offs
Overwriting cells to mark visits saves O(R x C) memory but destroys the input. A separate boolean grid is safer.
DFS is shorter to write for region problems; BFS is required for shortest paths and avoids deep recursion on large grids.
Variants and related techniques
Add the four diagonal offsets; used in Game of Life and shortest path in a binary matrix.
Cells with the same r - c share a top-left to bottom-right diagonal; the same r + c share an anti-diagonal.
Convert (r, c) to r * cols + c to use Union Find or adjacency-based algorithms.
Common mistakes
- Confusing rows and columns.
Fix: Use grid[row][col] consistently; rows = grid.length, cols = grid[0].length.
- Spiral revisits the middle row or column.
Fix: Check top <= bottom and left <= right before the third and fourth walks.
- Creating a 2D array with shared rows in JS.
Fix: new Array(r).fill(new Array(c)) shares one row. Use Array.from({ length: r }, () => new Array(c).fill(0)).
- Checking bounds after reading the cell.
Fix: Always check bounds first, then read.
Interview questions
How do you rotate an n x n matrix 90 degrees clockwise in place?
Transpose it (swap matrix[r][c] with matrix[c][r] for c > r), then reverse each row. For counter-clockwise, reverse each row first and then transpose.
Why start at the top-right corner for a sorted matrix search?
From there, moving left decreases values and moving down increases them, so every comparison eliminates a whole row or column: O(rows + cols).
How do you set matrix zeroes with O(1) extra space?
Use the first row and first column as marker arrays, with two flags to remember whether the first row and first column originally contained a zero.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 54. Spiral Matrix | Medium | Four boundaries and guard checks. |
| 48. Rotate Image | Medium | Transpose plus reverse. |
| 73. Set Matrix Zeroes | Medium | In-place markers. |
| 240. Search a 2D Matrix II | Medium | Staircase elimination. |
| 498. Diagonal Traverse | Medium | Direction switching on diagonals. |
| 289. Game of Life | Medium | 8 neighbors with in-place encoding. |