Given an m x n
matrix, return all elements of the matrix in spiral order.
For example:
Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: [1,2,3,6,9,8,7,4,5]
Input: matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
Output: [1,2,3,4,8,12,11,10,9,5,6,7]
Consider the following constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 10
-100 <= matrix[i][j] <= 100
How would you approach this problem? What are the edge cases that need consideration?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
Imagine walking around the edge of a square, then spiraling inward. The brute force approach is to meticulously trace that path, step-by-step, element-by-element. We simulate the process of traversing the matrix in a spiral manner.
Here's how the algorithm would work step-by-step:
def spiral_matrix(matrix):
if not matrix:
return []
result = []
start_row = 0
end_row = len(matrix) - 1
start_column = 0
end_column = len(matrix[0]) - 1
while start_row <= end_row and start_column <= end_column:
# Traverse right
for column_index in range(start_column, end_column + 1):
result.append(matrix[start_row][column_index])
start_row += 1
# Traverse down
for row_index in range(start_row, end_row + 1):
result.append(matrix[row_index][end_column])
end_column -= 1
# Need this check to avoid duplicate rows
if start_row <= end_row:
for column_index in range(end_column, start_column - 1, -1):
result.append(matrix[end_row][column_index])
end_row -= 1
# Need this check to avoid duplicate columns
if start_column <= end_column:
for row_index in range(end_row, start_row - 1, -1):
result.append(matrix[row_index][start_column])
start_column += 1
return result
The most efficient way to traverse a matrix in a spiral is to think of it as peeling layers. We repeatedly trace the outer boundaries, shrinking the matrix inwards with each iteration until everything is covered.
Here's how the algorithm would work step-by-step:
def spiral_matrix(matrix):
if not matrix:
return []
result = []
top_row = 0
bottom_row = len(matrix) - 1
left_column = 0
right_column = len(matrix[0]) - 1
while top_row <= bottom_row and left_column <= right_column:
# Traverse top row from left to right
for i in range(left_column, right_column + 1):
result.append(matrix[top_row][i])
top_row += 1
# Traverse right column from top to bottom
for i in range(top_row, bottom_row + 1):
result.append(matrix[i][right_column])
right_column -= 1
# Need to check if there is a row or column left
if top_row <= bottom_row:
# Traverse bottom row from right to left
for i in range(right_column, left_column - 1, -1):
result.append(matrix[bottom_row][i])
bottom_row -= 1
# Need to check if there is a row or column left
if left_column <= right_column:
# Traverse left column from bottom to top
for i in range(bottom_row, top_row - 1, -1):
result.append(matrix[i][left_column])
left_column += 1
return result
def solve():
matrix1 = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(spiral_matrix(matrix1))
matrix2 = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
]
print(spiral_matrix(matrix2))
matrix3 = [
[1, 2],
[3, 4]
]
print(spiral_matrix(matrix3))
if __name__ == "__main__":
solve()
Case | How to Handle |
---|---|
Null or Empty Matrix | Return an empty list immediately if the input matrix is null or has zero rows or columns. |
Single Row Matrix | Iterate through the single row from left to right and append each element to the result list. |
Single Column Matrix | Iterate through the single column from top to bottom and append each element to the result list. |
Square Matrix (n x n) | The algorithm should correctly handle square matrices as a general case of rectangular matrices. |
Rectangular Matrix (m x n, m != n) | The algorithm needs to adjust the boundaries correctly to avoid going out of bounds when rows and columns are different. |
Matrix with all identical elements | The algorithm should correctly traverse the matrix regardless of the values of the elements. |
Large Matrix (performance) | The iterative boundary shrinking approach should have a time complexity of O(m*n) and thus should scale linearly with input size, without excessive memory usage. |
Matrix with negative numbers, zeros, and large positive numbers | The algorithm should work correctly regardless of the range or sign of the matrix elements, as we only care about the indices and not the values themselves. |