Spiral Matrix
You're given an m x n matrix. Return all of its elements in spiral order: start at the top-left corner, move right along the top row, down the right column, left along the bottom row, and up the left column, then repeat on the remaining inner rectangle until every element is visited once.
Examples
matrix = [[5,1,9],[2,8,3],[7,6,4]] returns [5,1,9,3,4,6,7,2,8]
The outer ring is read clockwise from 5 back up to 2, and then the single center cell 8 is all that remains.
matrix = [[2,4,6],[8,10,12]] returns [2,4,6,12,10,8]
With two rows, the walk goes right across the top and left across the bottom, and nothing is left inside.
matrix = [[7],[8],[9]] returns [7,8,9]
A single column is read straight down. No element may be visited twice on the way back up.
Constraints
- 1 <= m, n <= 10
- -100 <= matrix[i][j] <= 100
Hints
The spiral is a series of shrinking rectangles. What do you need to track to know which rectangle is left?
Track top, bottom, left, and right boundaries, and shrink one each time you finish a side.
Loop while top <= bottom and left <= right: read the top row, then the right column, then the bottom row if top <= bottom still holds, then the left column if left <= right still holds.
Drill This: Your Approach First
Approach
Keep four boundaries, top, bottom, left, and right, for the rectangle still unread. Each lap reads the top row left to right and moves top down, then the right column top to bottom and moves right in. Before reading the bottom row right to left, check that top <= bottom, and before reading the left column bottom to top, check that left <= right, since a single leftover row or column would otherwise be read twice. Stop when the boundaries cross. O(m * n) time, O(1) extra space beyond the output.
Time
O(m * n)
Space
O(1) beyond the output
Pitfall
Solutions
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> out = new ArrayList<>();
int top = 0, bottom = matrix.length - 1;
int left = 0, right = matrix[0].length - 1;
while (top <= bottom && left <= right) {
for (int c = left; c <= right; c++) out.add(matrix[top][c]);
top++;
for (int r = top; r <= bottom; r++) out.add(matrix[r][right]);
right--;
if (top <= bottom) {
for (int c = right; c >= left; c--) out.add(matrix[bottom][c]);
bottom--;
}
if (left <= right) {
for (int r = bottom; r >= top; r--) out.add(matrix[r][left]);
left++;
}
}
return out;
}
}class Solution:
def spiralOrder(self, matrix):
out = []
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):
out.append(matrix[top][c])
top += 1
for r in range(top, bottom + 1):
out.append(matrix[r][right])
right -= 1
if top <= bottom:
for c in range(right, left - 1, -1):
out.append(matrix[bottom][c])
bottom -= 1
if left <= right:
for r in range(bottom, top - 1, -1):
out.append(matrix[r][left])
left += 1
return out