Skip to content

Matrix ProblemsπŸ”—

Matrix TraversalπŸ”—

  • SSince travel is possible from any (i, j) position in four/eight directions, use a direction vector to solve the problem of traversing the matrix efficiently.

DFSπŸ”—

vector<vector<int>> dirs = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

void dfs(vector<vector<int>>& grid, int i, int j, vector<vector<int>>& vis) {
  vis[i][j] = true;
  for(auto dir: dirs) {
    int x = i + dir[0];
    int y = j + dir[1];

    if(x < 0 || y < 0 || x >= grid.size() || y >= grid[0].size())
        continue;
    if(vis[x][y])
        continue;
    dfs(grid, x, y, vis);
  }
}

BFSπŸ”—

vector<vector<int>> dirs = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
queue<pair<int, int>> q;
q.push({sr, sc});

while(!q.empty()) {
  auto const &[i, j] = q.front(); q.pop();
    vis[i][j] = true;
  for(auto dir: dirs) {
    int x = i + dir[0];
    int y = j + dir[1];

    if(x < 0 || y < 0 || x >= grid.size() || y >= grid[0].size())
        continue;
    if(vis[x][y])
        continue;
    q.push({x, y});
  }
}

SpiralπŸ”—

vector<int> spiralOrder(vector<vector<int>>& matrix) {
    if(matrix.empty()) return {};
    int m = matrix.size(), n = matrix[0].size();
    int top = 0, bottom = m - 1;
    int left = 0, right = n - 1;
    vector<int> result;

    while (top <= bottom && left <= right) {
        // Traverse from left to right
        for (int j = left; j <= right; j++) {
            result.push_back(matrix[top][j]);
        }
        top++;

        // Traverse downwards
        for (int i = top; i <= bottom; i++) {
            result.push_back(matrix[i][right]);
        }
        right--;

        if (top <= bottom) {
            // Traverse from right to left
            for (int j = right; j >= left; j--) {
                result.push_back(matrix[bottom][j]);
            }
            bottom--;
        }

        if (left <= right) {
            // Traverse upwards
            for (int i = bottom; i >= top; i--) {
                result.push_back(matrix[i][left]);
            }
            left++;
        }
    }
    return result;
}

A more elegant python solution is to rotate array and consume first row.

def spirallyTraverse(self, matrix):
    result = []
    while matrix:
        result += matrix.pop(0)
        matrix = list(zip(*matrix))[::-1]
    return resul

Zig-ZagπŸ”—

  • Pretty Intuitive Traversal

Matrix Rotation & TransformationπŸ”—

  • Rotation by 90 degrees (clockwise)
    • For an matrix , the element at position moves to
    • Common approach:
      • Transpose the matrix: swap M[i][j] with M[j][i]
      • Reverse each row.
  • Rotation by 90 degrees (counter clockwise)
    • Transpose the Matrix
    • Reverse each columns
    • or do the reverse each row, then transpose
  • General Transformations
    • Translation
    • Scaling
    • Rotation by angle

Prefix 2D SumπŸ”—

int m = matrix.size();
int n = matrix[0].size();
vector<vector<int>> prefix(m, vector<int>(n, 0));

for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
        int top = (i > 0) ? prefix[i-1][j] : 0;
        int left = (j > 0) ? prefix[i][j-1] : 0;
        int diag = (i > 0 && j > 0) ? prefix[i-1][j-1] : 0;
        prefix[i][j] = matrix[i][j] + top + left - diag;
    }
}

Querying Submatrix SumπŸ”—

      (r1, c1)
         +---------------+
         |               |
         |     SUM       |
         |               |
         +---------------+
                         (r2, c2)


total = P[r2][c2]
if r1 > 0: total -= P[r1-1][c2]
if c1 > 0: total -= P[r2][c1-1]
if r1 > 0 and c1 > 0: total += P[r1-1][c1-1]

ApplicationπŸ”—

  • Image Processing
  • Histogram or Heatmap Analysis
  • DP Optimization on 2D Grids

Binary Search in Sorted MatrixπŸ”—

  • Naive Method is to put all numbers in a vector then sort and search.
def searchMatrix(matrix, target):
    if not matrix or not matrix[0]:
        return False

    n, m = len(matrix), len(matrix[0])
    low, high = 0, n * m - 1

    while low <= high:
        mid = (low + high) // 2
        row, col = divmod(mid, m)
        mid_val = matrix[row][col]

        if mid_val == target:
            return True
        elif mid_val < target:
            low = mid + 1
        else:
            high = mid - 1

    return False

Pathfinding in GridsπŸ”—

DijkstraπŸ”—

import heapq

def dijkstra(grid, start, goal):
    n, m = len(grid), len(grid[0])
    dist = [[float('inf')] * m for _ in range(n)]
    dist[start[0]][start[1]] = 0
    pq = [(0, start[0], start[1])]  # (cost, x, y)

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

    while pq:
        cost, x, y = heapq.heappop(pq)
        if (x, y) == goal:
            return cost
        for dx, dy in dirs:
            nx, ny = x+dx, y+dy
            if 0<=nx<n and 0<=ny<m and grid[nx][ny] != -1:
                new_cost = cost + grid[nx][ny]
                if new_cost < dist[nx][ny]:
                    dist[nx][ny] = new_cost
                    heapq.heappush(pq, (new_cost, nx, ny))
    return -1

A*πŸ”—

Use When: You want Dijkstra + heuristics (e.g., Euclidean or Manhattan distance)

Guarantees: Optimal + faster than Dijkstra (if heuristic is admissible)

def manhattan(x1, y1, x2, y2):
    return abs(x1 - x2) + abs(y1 - y2)

def astar(grid, start, goal):
    n, m = len(grid), len(grid[0])
    open_set = [(0 + manhattan(*start, *goal), 0, start[0], start[1])]  # (f = g + h, g, x, y)
    g_score = [[float('inf')] * m for _ in range(n)]
    g_score[start[0]][start[1]] = 0

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

    while open_set:
        f, g, x, y = heapq.heappop(open_set)
        if (x, y) == goal:
            return g
        for dx, dy in dirs:
            nx, ny = x+dx, y+dy
            if 0<=nx<n and 0<=ny<m and grid[nx][ny] == 0:
                ng = g + 1
                if ng < g_score[nx][ny]:
                    g_score[nx][ny] = ng
                    f_score = ng + manhattan(nx, ny, *goal)
                    heapq.heappush(open_set, (f_score, ng, nx, ny))
    return -1

Matrix ExponentiationπŸ”—

https://codeforces.com/blog/entry/67776

  • Powerful technique that can be used compute the terms of linear recurrence relations efficiently.
  • General Recurrence relation looks like : , where could be zero, implying no dependence on that term.
  • Let’s consider simple case of
  • Consider this matrix

  • And the column vector

  • Its straightforward to see first entries of . The entry is just the calculation of recurrence relation using the past k values of the sequence.So, when we obtain , the first entry gives . It is easy to see that is the first entry of the vector: (Here is the matrix multiplication of T with itself n times).
  • Example Matrix for Finbonacci sequence

  • Main Crux of Problem is getting the matrix
  • Problem: Let’s write T, F matrix for
  • Solution for

  • term will still be first entry of
  • To calculate , use the concept of binary exponentiation to calculate it in

Binary ExponentiationπŸ”—

  • This requires two function, one to multiply matrices, and second to perform exponentiation
def mat_mult(A, B, mod=None):
    n = len(A)
    res = [[0] * n for _ in range(n)]
    for i in range(n):
        for j in range(n):
            for k in range(n):
                res[i][j] += A[i][k] * B[k][j]
                if mod:
                    res[i][j] %= mod
    return res

def mat_pow(mat, power, mod=None):
    n = len(mat)
    result = [[1 if i == j else 0 for j in range(n)] for i in range(n)]  # Identity matrix
    while power > 0:
        if power % 2 == 1:
            result = mat_mult(result, mat, mod)
        mat = mat_mult(mat, mat, mod)
        power //= 2
    return result

# finbonacci in O(log n)
def fib(n):
    if n == 0:
        return 0
    base = [
        [1, 1],
        [1, 0]
    ]
    res = mat_pow(base, n - 1)
    return res[0][0]