DSA Topics
🔍
HomeData StructuresArrays Part
📊 Arrays — Part 2

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.

MatrixGridRow-MajorBFS/DFSDynamic Programming

💡 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.

matrix = [[1,2,3],[4,5,6],[7,8,9]] — Row-major layout
idx 0
1
+0B
idx 1
2
+4B
idx 2
3
+8B
idx 3
4
+12B
idx 4
5
+16B
idx 5
6
+20B
matrix[1][2] → row 1, col 2 → value 6
💡 Row-Major vs Column-Major
Python stores 2D arrays in row-major order — elements of the same row are adjacent in memory. Iterating row by row is faster due to CPU cache locality.

// 02 — Creation

Creating 2D Arrays

Correct way — List Comprehension

python
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]] ← BUG

With initial values

python
# 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]]
⚠️ Never use [[val]*cols]*rows
This is the most common 2D array bug in Python. Always use list comprehension: [[0]*cols for _ in range(rows)]

// 03 — Access & Update

Accessing & Updating Elements

Read & Write — O(1)

python
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])     # 3

Row and Column Operations

python
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)

python
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

python
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 9

Diagonal Traversal

python
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

python
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

python
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

python
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

Pattern 1Spiral Order Traversal

Traverse matrix in spiral: right → down → left → up. Shrink boundaries each pass.

python
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)
Pattern 2BFS / DFS on Grid

Treat each cell as a graph node. Use BFS for shortest path, DFS for connected regions.

python
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))
Pattern 32D Dynamic Programming

Build solution bottom-up using a DP table. Each cell depends on neighbors.

python
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

OperationAverageWorstNotes
Access element [i][j]O(1)O(1)
Traverse entire matrixO(m*n)O(m*n)
Search for valueO(m*n)O(m*n)
TransposeO(m*n)O(m*n)
Rotate 90°O(m*n)O(m*n)
Insert rowO(n)O(n)
BFS / DFS on gridO(m*n)O(m*n)
Use Arrays When
  • Grid / board problems (game of life, islands)
  • DP with two varying dimensions
  • Image or pixel manipulation
  • Adjacency matrix for dense graphs
🚫 Avoid Arrays When
  • 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.