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 ),我们以下图所示的方式遍历下方的元素和左侧的元素。

swift算法:螺旋矩阵_顺时针

时间复杂度: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

swift算法:螺旋矩阵_算法_02

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
    }