1、描述
给定一个包含 m x n 个元素的矩阵(m行,n列),请按照顺时针螺旋顺序,返回矩阵中的所有元素
例1:输入:[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
输出:[1, 2, 3, 6, 9, 8, 7, 4 ,5]
例2:输入:[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
]
输出:[1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]
2、算法
解法一:模拟
思路:绘制螺旋轨迹路径,我们发现当路径超出界限或者进入之前访问过的单元格时,会顺时针旋转方向。
步骤:
1)假设数组有R 行C 列,seen[r][c] 表示第 r 行第 c 列的单元格之前已经被访问过了。
2)当前所在位置为(r, c),前进方向是di。我们希望访问所有R xC 个单元格。
3)当我们遍历整个矩阵,下一步候选移动位置是(cr, cc)。
4)如果这个候选位置在矩阵范围内并且没有被访问过,那么它将会变成下一步移动的位置;否则,我们将前进方向顺时针旋转之后再计算下一步的移动位置。
时间复杂度:O(n)
func spiralOrder(_ matrix: [[Int]]) -> [Int] {
var ans : [Int] = [Int]()
if matrix.count == 0 {
return ans
}
let R = matrix.count
let C = matrix[0].count
var seen : [[Bool]] = [[Bool]].init(repeating: [Bool].init(repeating: false, count: C), count: R)
var dr = [0, 1, 0, -1]
var dc = [1, 0, -1, 0]
var r = 0, c = 0, di = 0
for i in 0..<R*C {
ans.append(matrix[r][c])
seen[r][c] = true
let cr = r + dr[di]
let cc = c+dc[di]
if 0<=cr && cr<R && 0<=cc && cc<C && !seen[cr][cc]{
r = cr
c = cc
}else{
di = (di+1)%4
r += dr[di]
c += dc[di]
}
}
return ans
}
解法二:按层模拟O(n)
思路:答案是最外层所有元素按照顺时针顺序输出,其次是次外层,以此类推。
步骤:
1)我们定义矩阵的第 k 层是到最近边界距离为 k 的所有顶点。例如,下图矩阵最外层元素都是第 1 层,次外层元素都是第 2 层,然后是第 3 层的。
2) 对于每层,我们从左上方开始以顺时针的顺序遍历所有元素,假设当前层左上角坐标是(r1, c1),右下角坐标是(r2, c2)。
3)首先,遍历上方的所有元素(r1, c),按照c = c1,...,c2 的顺序。
4)然后遍历右侧的所有元素(r, c2),按照r = r1+1,...,r2 的顺序。
5)如果这一层有四条边(也就是r1 < r2 并且c1 < c2 ),我们以下图所示的方式遍历下方的元素和左侧的元素。
时间复杂度:O(n)
func spiralOrder(_ matrix: [[Int]]) -> [Int] {
var ans : [Int] = [Int]()
if matrix.count == 0 {
return ans
}
var r1 = 0, r2 = matrix.count-1
var c1 = 0, c2 = matrix[0].count-1
while r1<=r2 && c1<=c2 {
//第一行的数 top
for c in c1...c2 {
ans.append(matrix[r1][c])
}
//最右边除了第一行的所有最后一个数 right
var r = r1+1
while r <= r2 {
ans.append(matrix[r][c2])
r += 1
}
//下边及左边最外层数
if r1<r2 && c1<c2 {
//bottom
var c = c2-1
while c > c1 {
ans.append(matrix[r2][c])
c -= 1
}
//left
var r = r2
while r>r1{
ans.append(matrix[r][c1])
r -= 1
}
}
r1 += 1
r2 -= 1
c1 += 1
c2 -= 1
}
return ans
}
解法三:从外向内遍历
思路:从外部向内部逐层遍历打印矩阵,最外面一圈打印完,里面仍然是一个矩阵
第i层矩阵的打印,需要经历4个循环
从左到右
从上倒下
从右往左,如果这一层只有1行,那么第一个循环已经将该行打印了,这里就不需要打印了,即 (m-1-i )!= i
从下往上,如果这一层只有1列,那么第2个循环已经将该列打印了,这里不需要打印,即(n-1-i) != i
func spiralOrder(_ matrix: [[Int]]) -> [Int] {
var ans : [Int] = [Int]()
if matrix.count == 0 {
return ans
}
let m = matrix.count
let n = matrix[0].count
var i = 0
//统计矩阵从外向内的层数,如果矩阵为空,那么它的层数至少是1层
let count = (min(m, n)+1)/2
//从外部向内部遍历,逐层打印数据
while i<count {
//从左到右
for j in i..<n-i {
ans.append(matrix[i][j])
}
//从上到下
for j in i+1..<m-i{
ans.append(matrix[j][(n-1)-i])
}
//从右往左,如果这一层只有1行,那么第一个循环已经将该行打印了,这里就不需要打印了,即 (m-1-i )!= i
var j = (n-1)-(i+1)
while j >= i && (m-1-i != i){
ans.append(matrix[m-1-i][j])
j -= 1
}
//从下往上,如果这一层只有1列,那么第2个循环已经将该列打印了,这里不需要打印,即(n-1-i) != i
var k = (m-1)-(i+1)
while k>=i+1 && (n-1-i != i){
ans.append(matrix[k][i])
k -= 1
}
i += 1
}
return ans
}