The problem
Given an m x n matrix, return all elements of the matrix in spiral order.
Examples
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]
Constraints
- m == matrix.length
- n == matrix[i].length
- 1 <= m, n <= 10
- -100 <= matrix[i][j] <= 100
Explanation
Let’s look at the example with matrix = [[1,2,3],[4,5,6],[7,8,9]] and try to figure out a way to solve this problem.
We are going to start from the top left corner:
- Go right from
1to2, - Go right again from
2to3, now we can’t go right anymore - Next, we go down from
3to6, - Go down one more time from
6to9, - Now we are going to go left from
9to8because we can’t go down anymore, - Go left again from
8to7 - We can’t go left anymore, so we go up from
7to4, and if we try to go up, we see that we already visited it and we can’t go there - Lastly, we go right from
4to5. If we try to go right, we can see that we cannot go right anymore because we already visited that element
To solve this problem we are going to start from the top left corner:
- Go right until we visit all of them
- Next, we go down and visit all available elements
- Next, we go left and visit all of the elements
- Next, we go up
We went through all four directions, but we still have some elements left.
- We took the outermost layer and shrank it. Now we have a sub-matrix, and we can do the same algorithm on it.
- We can do it by introducing
leftandrightboundaries that we move inward by1. - Similarly, we have
topandbottomboundaries that we also need to shrink by1. - After that, we are going to solve the sub-matrix in spiral order by going from
topleftto theright. - You can notice that we’ve gone through all elements, so now we can move our
leftandrightboundaries once more, and stop because we don’t have a rectangle anymore and we visited all elements.
Iteration Solution
func spiralOrder(_ matrix: [[Int]]) -> [Int] {
var res: [Int] = []
var l = 0
var r = matrix[0].count
var top = 0
var bottom = matrix.count
while l < r && top < bottom {
for i in l ..< r {
res.append(matrix[top][i])
}
top += 1
for i in top ..< bottom {
res.append(matrix[i][r - 1])
}
r -= 1
if !(l < r && top < bottom) {
break
}
for i in stride(from: r - 1, to: l - 1, by: -1) {
res.append(matrix[bottom - 1][i])
}
bottom -= 1
for i in stride(from: bottom - 1, to: top - 1, by: -1) {
res.append(matrix[i][l])
}
l += 1
}
return res
}
Explanation
We are going to initialize the left boundary at 0, right at len(matrix[0]), top at 0, and bottom at len(matrix) to solve this problem in an easier way and avoid edge cases.
We are always going to start at the top left position.
- After that, we are going to go
rightand iterate through the first row, adding values to our result until we reach ourrightboundary. - Now we can go
down, so we need to shift ourtopboundary down by1, add values to our result, and continue going down until we reach ourbottomboundary - We can see that we visited all elements in the last column, therefore we can now move our
rightboundary by decreasing it by1 - Next, we can go through elements to the
leftuntil we reach ourleftboundary and add those elements to our result - When we reach the
leftboundary, you can see that we also finished the entirebottomrow, meaning that we can shift ourbottomboundary up by1 - Next, we are going to go
upuntil we reach ourtopboundary, and add values to our result - When we reach our
topboundary we can update ourleftboundary by increasing it by1 - Next, we go
rightand add elements to our result until we reach ourrightboundary - Lastly, when the
leftboundary reaches therightboundary ortopreachesbottom, we will stop our algorithm because we’ve done every single element
Time/ Space complexity
- Time complexity: O(m*n)
- Space complexity: O(1) extra memory, O(m*n) for the output list
- Where
mis the number of rows, andnis the number of columns