DSA Guide
Matrix

Matrix

Reasoning about a grid by its rows, columns and layers — index arithmetic, in-place transforms, and the traps of shared references

A matrix is a grid of values: an array of arrays. grid[r][c] is row r, column c.

Most matrix problems are not about clever algorithms. They are about index arithmetic done carefully, and about changing a grid in place without destroying values you still need.

Reading the Coordinates

A 3 × 4 grid
0123
0
a
b
c
d
1
e
f
g
h
2
i
j
k
l
'f' is at row 1, column 1 — written grid[1][1]. Rows run down, columns run across.

Row first, then column — and it is not (x, y)

grid[r][c] means row r, column c. Rows go down, columns go across.

That is the opposite order from graph coordinates, where (x, y) means across then down. Mixing them up gives an index error on a rectangular grid and — far worse — silently wrong answers on a square one, where both are in range.

rows = len(grid)        how many rows      → the vertical size
cols = len(grid[0])     how many columns   → the horizontal size

Write those two lines first, every time. Reaching for len(grid) when you meant the width is the most common matrix bug.

The Four Neighbours

Most grid traversal needs the cells sharing an edge:

        (r-1, c)

(r, c-1) ─ (r,c) ─ (r, c+1)

        (r+1, c)

directions = [(-1,0), (1,0), (0,-1), (0,1)]

Storing them as a list and looping is shorter and less error-prone than writing four near-identical blocks — the copy-paste version is where a stray r that should be c hides.

Always check bounds before reading

0 <= nr < rows  and  0 <= nc < cols

In Python this matters twice over: grid[-1] is legal and silently wraps to the last row, so an unchecked negative index produces a plausible wrong answer rather than an error.

Diagonals add four more offsets. Whether they count is a decision the problem makes — check for it, because it is rarely stated in a sentence of its own.

Creating a Grid — the Reference Trap

This is the single most damaging matrix bug in both languages.

Never build rows by repeating one list

WRONG   grid = [[0] * cols] * rows

Creates ONE row and points every slot at it.
grid[0][0] = 1  →  every row now starts with 1.
RIGHT   grid = [[0] * cols for _ in range(rows)]

TypeScript has the identical trap:

WRONG   new Array(rows).fill(new Array(cols).fill(0))
RIGHT   Array.from({ length: rows }, () => new Array(cols).fill(0))

The outer repeat copies a reference, not the row. [0] * cols is safe because numbers are values; * rows on a list of lists is not.

The symptom is bizarre: writing one cell changes a whole column's worth of rows. It looks like a logic error anywhere but the line that caused it.

In Place Means Order Matters

Many matrix problems demand O(1) extra space — transform the grid without building a new one. That creates a hazard: every write destroys a value that something else might still need.

Two ways out, and both are worth knowing:

TechniqueIdeaUsed by
Swap in cyclesMove values around a closed loop, holding one in a temporaryRotate Image
Use the grid as its own notepadStore markers in a row or column you have already processedSet Matrix Zeroes

The second sounds like a hack and is a genuine technique: the first row and column can record which rows and columns need clearing, removing the need for two extra arrays.

The Transforms Worth Knowing

Several problems are combinations of two simple operations.

original        transpose        reverse each row
1 2 3           1 4 7            7 4 1
4 5 6     →     2 5 8      →     8 5 2
7 8 9           3 6 9            9 6 3

                                 = rotated 90° clockwise

Rotation is two reflections

WantDo
Rotate 90° clockwiseTranspose, then reverse each row
Rotate 90° anticlockwiseTranspose, then reverse each column
Rotate 180°Reverse the rows, then reverse each row

Deriving a rotation from scratch means getting a four-way index formula right. Composing two operations you can each verify by eye is far harder to get wrong — see Rotate Image.

Transpose swaps grid[r][c] with grid[c][r]. Note the loop must start at c = r, not c = 0 — otherwise every pair is swapped twice and the grid comes back unchanged.

Traversing in Layers

Spiral problems peel the grid like an onion. The reliable technique is four moving boundaries rather than direction-tracking logic:

top, bottom, left, right

→ walk the top row,     then top++
→ walk the right col,   then right--
→ walk the bottom row,  then bottom--
→ walk the left col,    then left++

repeat while top <= bottom and left <= right

The boundaries close in on each other and the loop ends when they cross. See Spiral Matrix for why the last two walks need an extra check.

All Problems

ProblemDifficultyPattern
Transpose MatrixEasyIndex swapping
Rotate ImageMediumTranspose then reverse, in place
Spiral MatrixMediumShrinking boundaries
Set Matrix ZeroesMediumThe grid as its own storage

Suggested order

Transpose Matrix first — it is pure index arithmetic and teaches the c = r starting point that Rotate Image then depends on.

Spiral Matrix is independent and can be done any time. Set Matrix Zeroes is the hardest of the four, because the O(1) version requires trusting the grid to store its own bookkeeping.

On this page