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
1
to2
, - Go right again from
2
to3
, now we can’t go right anymore - Next, we go down from
3
to6
, - Go down one more time from
6
to9
, - Now we are going to go left from
9
to8
because we can’t go down anymore, - Go left again from
8
to7
- We can’t go left anymore, so we go up from
7
to4
, 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
4
to5
. 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
left
andright
boundaries that we move inward by1
. - Similarly, we have
top
andbottom
boundaries that we also need to shrink by1
. - After that, we are going to solve the sub-matrix in spiral order by going from
top
left
to theright
. - You can notice that we’ve gone through all elements, so now we can move our
left
andright
boundaries 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
right
and iterate through the first row, adding values to our result until we reach ourright
boundary. - Now we can go
down
, so we need to shift ourtop
boundary down by1
, add values to our result, and continue going down until we reach ourbottom
boundary - We can see that we visited all elements in the last column, therefore we can now move our
right
boundary by decreasing it by1
- Next, we can go through elements to the
left
until we reach ourleft
boundary and add those elements to our result - When we reach the
left
boundary, you can see that we also finished the entirebottom
row, meaning that we can shift ourbottom
boundary up by1
- Next, we are going to go
up
until we reach ourtop
boundary, and add values to our result - When we reach our
top
boundary we can update ourleft
boundary by increasing it by1
- Next, we go
right
and add elements to our result until we reach ourright
boundary - Lastly, when the
left
boundary reaches theright
boundary ortop
reachesbottom
, 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
m
is the number of rows, andn
is the number of columns