swift Algorithm: Spiral Matrix

1. Description

Given a matrix of mxn elements (m row, n-column), follow a helical clockwise order, returns all the elements of the matrix

Example 1: Input: [

                        [1, 2, 3],

                        [4, 5, 6],

                         [7, 8, 9]

                     ]

          Output: [1, 2, 3, 6, 9, 8, 7, 4, 5]

Example 2: Input: [

                        [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]

 

2, algorithm

Solution one: Analog

Thinking: when drawing a spiral path trajectory, we found that when the path is out of bounds or into a cell previously visited, will rotate clockwise.

 step:

1) Suppose the array has R rows and C columns, seen [r] [c] represents has been visited before the cell at row r column c of a.

2) for the current location (r, c), the forward direction is di. We want access to all R xC a cell.

 3) When we traverse the entire matrix, the next candidate position is moved (cr, cc).

4) If the candidate position matrix within range and has not been visited, then it will become the next moved position; otherwise, we will proceed next shift position recalculated after the rotation in the clockwise direction.

Time complexity: 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
    }

Solution II: Analog layer by O (n)

Idea: The answer is the outermost layer of all elements of the output in a clockwise order, followed by the second layer, and so on.

step:

1) we define the k-th layer of the matrix is the nearest to the boundary distance of all vertices k. For example, the outermost FIG matrix elements are a first layer, the second layer are views outer element 2, then the layer 3.
2) for each layer, from the upper left in clockwise order through all the elements, it assumed that the current layer is the upper left corner coordinates (r1, c1), the lower right corner coordinates (r2, c2).
3) First, through all the elements of the above (r1, c), in accordance with c = c1, ..., c2 order.

4) all the elements then traverse right side (r, c2), according to r = r1 + 1, ..., r2 order.

5) If this layer has four sides (i.e. r1 <r2 and c1 <c2), the following embodiment shown in FIG we traverse the elements of the left and below the element.

Time complexity: 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
    }

Solution three: traversing from the outside

Ideas: traversing print matrix layer by layer from the outside to the inside, the outermost circle printed, there is still a matrix

Printing of the i-layer matrix, to go through four cycles

         From left to right

         From the fall

         From right to left, if this layer is only one line, then the first cycle of the line has been printed, there is no need printed, i.e. (m-1-i)! = I

         Up, if only one layer, then the second cycle has been printed from the column, and there is no need to print, i.e., (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
    }

 

Guess you like

Origin blog.csdn.net/lin1109221208/article/details/93211959