2D Arrays — Grids & Matrices Explained
Master 2D arrays to solve grid problems, DP tables, image processing and graph adjacency matrices. Foundation for 30% of medium/hard interview problems.
💡 Note: Python uses lists of lists for 2D arrays. Always use list comprehension to avoid the aliasing bug.
// 01 — Introduction
What is a 2D Array?
A 2D array is an array of arrays — a grid of rows and columns. Think of it as a table or matrix. Every cell is accessed using two indices: matrix[row][col].
Used in: image processing, dynamic programming (DP tables), graph adjacency matrices, game boards (chess, tic-tac-toe), spreadsheets.
// 02 — Creation
Creating 2D Arrays
Correct way — List Comprehension
rows, cols = 3, 4
# ✅ CORRECT — each row is independent
matrix = [[0] * cols for _ in range(rows)]
# [[0,0,0,0], [0,0,0,0], [0,0,0,0]]
# ❌ WRONG — all rows share same list!
bad = [[0] * cols] * rows
bad[0][0] = 99
print(bad) # [[99,0,0,0],[99,0,0,0],[99,0,0,0]] ← BUGWith initial values
# From nested list
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Identity matrix
n = 3
identity = [[1 if i == j else 0 for j in range(n)] for i in range(n)]
# [[1,0,0],[0,1,0],[0,0,1]]
# From flat list
flat = [1,2,3,4,5,6]
rows, cols = 2, 3
grid = [flat[i*cols:(i+1)*cols] for i in range(rows)]
# [[1,2,3],[4,5,6]][[0]*cols for _ in range(rows)]// 03 — Access & Update
Accessing & Updating Elements
Read & Write — O(1)
matrix = [[1,2,3],[4,5,6],[7,8,9]]
# Read
print(matrix[0][0]) # 1 — top-left
print(matrix[1][2]) # 6 — row 1, col 2
print(matrix[-1][-1]) # 9 — bottom-right
# Update
matrix[0][1] = 99
print(matrix[0]) # [1, 99, 3]
# Dimensions
rows = len(matrix) # 3
cols = len(matrix[0]) # 3Row and Column Operations
matrix = [[1,2,3],[4,5,6],[7,8,9]]
# Get entire row
row1 = matrix[1] # [4, 5, 6]
# Get entire column (no shortcut — must iterate)
col1 = [matrix[r][1] for r in range(len(matrix))] # [2, 5, 8]
# Get diagonal
diag = [matrix[i][i] for i in range(len(matrix))] # [1, 5, 9]// 04 — Traversal
Traversal Techniques
Row by Row (most common)
matrix = [[1,2,3],[4,5,6],[7,8,9]]
# Basic nested loop
for i in range(len(matrix)):
for j in range(len(matrix[0])):
print(matrix[i][j], end=' ')
# Cleaner — for-in
for row in matrix:
for val in row:
print(val, end=' ')
# With indices — enumerate
for i, row in enumerate(matrix):
for j, val in enumerate(row):
print(f"[{i}][{j}]={val}", end=' ')Column by Column
rows, cols = len(matrix), len(matrix[0])
for j in range(cols):
for i in range(rows):
print(matrix[i][j], end=' ')
# 1 4 7 2 5 8 3 6 9Diagonal Traversal
n = len(matrix)
# Main diagonal (top-left → bottom-right)
for i in range(n):
print(matrix[i][i]) # 1, 5, 9
# Anti-diagonal (top-right → bottom-left)
for i in range(n):
print(matrix[i][n-1-i]) # 3, 5, 7// 05 — Operations
Common Matrix Operations
Transpose — Flip rows and columns
matrix = [[1,2,3],[4,5,6],[7,8,9]]
# Method 1 — zip (most Pythonic)
transposed = [list(row) for row in zip(*matrix)]
# [[1,4,7],[2,5,8],[3,6,9]]
# Method 2 — manual
rows, cols = len(matrix), len(matrix[0])
T = [[matrix[j][i] for j in range(rows)] for i in range(cols)]Rotate 90° Clockwise
def rotate_90_clockwise(matrix):
n = len(matrix)
# Step 1: Transpose
for i in range(n):
for j in range(i+1, n):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
# Step 2: Reverse each row
for row in matrix:
row.reverse()
return matrix
# [[1,4,7],[2,5,8],[3,6,9]] → [[7,4,1],[8,5,2],[9,6,3]]Flatten 2D to 1D
matrix = [[1,2,3],[4,5,6],[7,8,9]]
# List comprehension
flat = [val for row in matrix for val in row]
# [1,2,3,4,5,6,7,8,9]
# sum trick
flat2 = sum(matrix, [])
# [1,2,3,4,5,6,7,8,9]// 06 — Patterns
3 Essential 2D Array Patterns
Traverse matrix in spiral: right → down → left → up. Shrink boundaries each pass.
def spiral_order(matrix):
result = []
top, bottom = 0, len(matrix) - 1
left, right = 0, len(matrix[0]) - 1
while top <= bottom and left <= right:
for c in range(left, right+1): result.append(matrix[top][c])
top += 1
for r in range(top, bottom+1): result.append(matrix[r][right])
right -= 1
if top <= bottom:
for c in range(right, left-1, -1): result.append(matrix[bottom][c])
bottom -= 1
if left <= right:
for r in range(bottom, top-1, -1): result.append(matrix[r][left])
left += 1
return result
# Time: O(m*n) | Space: O(1)Treat each cell as a graph node. Use BFS for shortest path, DFS for connected regions.
from collections import deque
def num_islands(grid):
rows, cols = len(grid), len(grid[0])
count = 0
def bfs(r, c):
q = deque([(r, c)])
grid[r][c] = '0'
while q:
row, col = q.popleft()
for dr, dc in [(1,0),(-1,0),(0,1),(0,-1)]:
nr, nc = row+dr, col+dc
if 0<=nr<rows and 0<=nc<cols and grid[nr][nc]=='1':
grid[nr][nc] = '0'
q.append((nr, nc))
for r in range(rows):
for c in range(cols):
if grid[r][c] == '1':
bfs(r, c)
count += 1
return count
# Time: O(m*n) | Space: O(min(m,n))Build solution bottom-up using a DP table. Each cell depends on neighbors.
def unique_paths(m, n):
dp = [[1] * n for _ in range(m)]
for i in range(1, m):
for j in range(1, n):
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
# Robot can only move right or down
# dp[i][j] = ways to reach cell (i,j)
print(unique_paths(3, 7)) # 28
# Time: O(m*n) | Space: O(m*n)// 07 — Complexity
Time & Space Complexity
| Operation | Average | Worst | Notes |
|---|---|---|---|
| Access element [i][j] | O(1) | O(1) | |
| Traverse entire matrix | O(m*n) | O(m*n) | |
| Search for value | O(m*n) | O(m*n) | |
| Transpose | O(m*n) | O(m*n) | |
| Rotate 90° | O(m*n) | O(m*n) | |
| Insert row | O(n) | O(n) | |
| BFS / DFS on grid | O(m*n) | O(m*n) |
- Grid / board problems (game of life, islands)
- DP with two varying dimensions
- Image or pixel manipulation
- Adjacency matrix for dense graphs
- Sparse data → use HashMap instead
- When rows have different lengths → use list of lists
- Very large grids → consider sparse matrix
- When only 1D traversal needed
// 08 — Practice Problems
Curated Problem Set
Solve in order — Easy → Medium → Hard.