Spiral Matrix

Medium Arrays & Hashing Matrix Traversal Original on LeetCode

Reported atMicrosoftAdobe

Spiral Matrix is a medium arrays & hashing problem solved with the matrix traversal pattern. The best approach, optimal (shrinking boundaries), runs in O(m · n) time and O(1) space. Below are 2 approaches in Java, Python, C++ and JavaScript, from brute force (simulate with a visited grid) up.

Problem

Given an m x n integer matrix, return all of its elements in spiral order: start at the top-left corner, move right along the first row, then down the last column, left along the last row, up the first column, and keep circling inward clockwise until every element has been listed once.

Examples

Example 1

Input
matrix = [[10, 11, 12, 13], [20, 21, 22, 23], [30, 31, 32, 33]]
Output
[10, 11, 12, 13, 23, 33, 32, 31, 30, 20, 21, 22]
Why
Go right along the top row, down the right column, left along the bottom row, up the left column, then the remaining inner row 21, 22.

Example 2

Input
matrix = [[3, 8, 1], [6, 2, 7]]
Output
[3, 8, 1, 7, 2, 6]
Why
After the outer ring there is nothing left inside.

Example 3

Input
matrix = [[5], [9], [4]]
Output
[5, 9, 4]
Why
A single column is read straight down.

Constraints

  • m == matrix.length, n == matrix[i].length
  • 1 <= m, n <= 100
  • -1000 <= matrix[i][j] <= 1000

Solve it here

Write your solution in Java, Python, C++ or JavaScript and run it against the examples, right in the page. Submit runs the hidden tests too and, with a free account, records the solve in your revision log.

00:00
Testcase

Run checks the testcases above (3 examples, or your own). Submit also runs 12 hidden tests and saves the solve to your log. Signed in, every Run and Submit is saved under My submissions; your draft stays in this browser.

Solutions

Try it yourself first. Then compare: each approach lists its idea, the steps, its time and space, and the code in Java, Python, C++ and JavaScript.

ApproachTimeSpace
Brute force (simulate with a visited grid)O(m · n)O(m · n)
Optimal (shrinking boundaries)O(m · n)O(1)

1Brute force (simulate with a visited grid)

TimeO(m · n)Every cell is visited once with constant work.
SpaceO(m · n)The visited grid has one flag per cell.

Walk like a robot: start at the top-left heading right, and turn clockwise whenever the next cell is outside the matrix or already visited. A separate boolean grid remembers visited cells.

  1. Directions in order: right, down, left, up.
  2. Repeat m * n times: record the cell, mark it visited, compute the next cell.
  3. If the next cell is out of range or visited, turn to the next direction and recompute.
class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        boolean[][] seen = new boolean[m][n];
        int[] dr = { 0, 1, 0, -1 }, dc = { 1, 0, -1, 0 };
        List<Integer> res = new ArrayList<>();
        int r = 0, c = 0, d = 0;
        for (int k = 0; k < m * n; k++) {
            res.add(matrix[r][c]);
            seen[r][c] = true;
            int nr = r + dr[d], nc = c + dc[d];
            if (nr < 0 || nr >= m || nc < 0 || nc >= n || seen[nr][nc]) {
                d = (d + 1) % 4;
                nr = r + dr[d];
                nc = c + dc[d];
            }
            r = nr;
            c = nc;
        }
        return res;
    }
}

2Optimal (shrinking boundaries)

TimeO(m · n)Each cell is read exactly once.
SpaceO(1)Four integers besides the output list.

Track the unread rectangle with four boundaries. Read its top row, right column, bottom row and left column in that order, pulling each boundary inward after its side is read. Guard the bottom row and left column so a single leftover row or column is not read twice.

  1. top = 0, bottom = m - 1, left = 0, right = n - 1.
  2. While top <= bottom and left <= right: read top row left to right, then top++.
  3. Read right column top to bottom, then right--.
  4. If top <= bottom: read bottom row right to left, then bottom--.
  5. If left <= right: read left column bottom to top, then left++.
class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> res = new ArrayList<>();
        int top = 0, bottom = matrix.length - 1, left = 0, right = matrix[0].length - 1;
        while (top <= bottom && left <= right) {
            for (int c = left; c <= right; c++) res.add(matrix[top][c]);
            top++;
            for (int r = top; r <= bottom; r++) res.add(matrix[r][right]);
            right--;
            if (top <= bottom) {
                for (int c = right; c >= left; c--) res.add(matrix[bottom][c]);
                bottom--;
            }
            if (left <= right) {
                for (int r = bottom; r >= top; r--) res.add(matrix[r][left]);
                left++;
            }
        }
        return res;
    }
}

Edge cases to test

  • A single row or a single column
  • A 1 x 1 matrix
  • Wide or tall rectangles where the last layer is one row or one column, which must not be read twice

Hints

Hint 1

Think of the matrix as nested rings. Each ring is read top row, right column, bottom row, left column.

Hint 2

Keep four boundaries: top, bottom, left, right. After reading a side, move that boundary inward.

Hint 3

Before reading the bottom row or the left column, check that the boundaries have not crossed, or a lone middle row or column gets read twice.

FAQ

What is the best time complexity for Spiral Matrix?

Optimal (shrinking boundaries) runs in O(m · n) time and O(1) extra space. Each cell is read exactly once.

Which pattern does Spiral Matrix use?

It is a arrays & hashing problem that uses the matrix traversal pattern.

Is there a brute force solution for Spiral Matrix?

Yes. Brute force (simulate with a visited grid) takes O(m · n) time and O(m · n) space. Walk like a robot: start at the top-left heading right, and turn clockwise whenever the next cell is outside the matrix or already visited.

Which edge cases should I test for Spiral Matrix?

A single row or a single column; A 1 x 1 matrix; Wide or tall rectangles where the last layer is one row or one column, which must not be read twice.