Matrix Algorithms: Code Templates in 6 Languages
If you have not read the concept guide yet, start there for the coordinate system and the boundary rules. This page gives you the code you can memorize and adapt during an interview. Every template runs in time proportional to the number of cells,
Main Template: Grid Traversal with Boundary Checks
This is the foundation of every matrix algorithm. A double loop visits every cell once, and each cell can reach its four neighbors with a bounds check on each one. Most matrix problems start from this skeleton and add a condition inside the loop.
Use this for the traversal-based problems on the practice problems page, including Reshape the Matrix and Transpose Matrix .
function traverseGrid(grid) {
const rows = grid.length;
const cols = grid[0].length;
const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
// The current cell is in bounds by construction.
// Neighbors are not, so each candidate gets validated.
for (const [dr, dc] of directions) {
const nr = r + dr;
const nc = c + dc;
// Edges have fewer than four neighbors, so skip
// any candidate that lands outside the grid.
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) {
// process grid[nr][nc]
}
}
}
}
}Code Breakdown
Key Variables
rowsandcols: the grid dimensions, read once at the start. Every bounds check compares against these two values, so they stay in scope for the whole function.randc: the current cell’s row and column. The inner loop advancescto the end of the row, then resets it to 0 whileradvances.directions: the four neighbor offsets. One entry per direction, and every one is applied with the same bounds check.nrandnc: the candidate neighbor coordinates. They are validated before any access happens.
Visual Mechanism
graph TD
A["Cell (r,c)"] --> B{"Neighbor inside grid?"}
B -->|"0 <= nr < rows and 0 <= nc < cols"| C["Access grid[nr][nc]"]
B -->|No| D["Skip candidate"]
C --> E["Move to next direction"]
D --> E
Critical Sections
The initialization reads rows and cols once and reuses them everywhere. Reading grid[0].length inside the loop is a subtle trap. It repeats work and it breaks on jagged input, where one row has a different length from the others. One read up front keeps the bounds consistent for every cell.
The neighbor loop is where the bounds check lives. Each of the four offsets is applied to the current cell, and the candidate is validated before access. Skipping that check is the single most common matrix bug, and it only fails on edge rows and columns.
The termination is implicit in the loop conditions. c advances to cols, then resets with r incrementing. When r reaches rows, every cell has been visited exactly once, so the loop cannot double-count or skip a cell.
Variations
1. Grid DFS with Visited Marking
When the problem asks you to explore a connected region, the recursive DFS form is the template to memorize. The visited marking matters more than the recursion. A cell is claimed before its neighbors are explored, so overlapping paths cannot revisit it.
Use this for flood-fill and island-counting problems. Number of Islands appears on the Union Find problems page , and Longest Increasing Path in a Matrix extends this skeleton with a memo table instead of a visited set.
function floodFill(grid, startR, startC) {
const rows = grid.length, cols = grid[0].length;
const visited = new Set();
function dfs(r, c) {
if (r < 0 || r >= rows || c < 0 || c >= cols) return;
const key = r + "," + c;
if (visited.has(key)) return;
// Claim the cell before exploring so the neighbors
// cannot schedule it again through another path.
visited.add(key);
dfs(r - 1, c);
dfs(r + 1, c);
dfs(r, c - 1);
dfs(r, c + 1);
}
dfs(startR, startC);
}This template runs in
2. Spiral Traversal
Spiral order replaces loop counters with four boundaries that shrink as each side is consumed. The guards after the first two passes exist because the remaining grid can be a single row or a single column.
Use this for Spiral Matrix .
function spiralOrder(matrix) {
const result = [];
if (matrix.length === 0) return result;
let top = 0, bottom = matrix.length - 1;
let left = 0, right = matrix[0].length - 1;
while (top <= bottom && left <= right) {
// Right along the top row, then the top edge is done.
for (let j = left; j <= right; j++) result.push(matrix[top][j]);
top++;
// Down the right column, then the right edge is done.
for (let i = top; i <= bottom; i++) result.push(matrix[i][right]);
right--;
// The grid may now be a single row, so guard the pass.
if (top <= bottom) {
for (let j = right; j >= left; j--) result.push(matrix[bottom][j]);
bottom--;
}
// The grid may now be a single column, so guard the pass.
if (left <= right) {
for (let i = bottom; i >= top; i--) result.push(matrix[i][left]);
left++;
}
}
return result;
}Runs in
3. In-Place Rotation
A 90-degree clockwise rotation is a transpose followed by reversing each row. Transposing alone swaps the cell pairs across the diagonal. The row reversal then moves every column into its rotated position. Both steps work in place for square matrices.
Use this for Rotate Image .
function rotate(matrix) {
const n = matrix.length;
// Transpose: swap across the main diagonal. Only j > i
// is needed because the swap covers both sides.
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
[matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]];
}
}
// Reverse each row to complete the clockwise rotation.
for (let i = 0; i < n; i++) {
matrix[i].reverse();
}
}Runs in
Now head to the practice problems to apply these templates to real interview questions.