|
| 1 | +# 毎日一题 - 54.Spiral Matrix |
| 2 | + |
| 3 | +## 信息卡片 |
| 4 | + |
| 5 | +- 时间:2019-07-29 |
| 6 | +- 题目链接:https://leetcode.com/problems/spiral-matrix/ |
| 7 | +- tag:`Array` `Matrix` |
| 8 | + |
| 9 | +## 题目描述 |
| 10 | + |
| 11 | +``` |
| 12 | +Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order. |
| 13 | +
|
| 14 | +Example 1: |
| 15 | +
|
| 16 | + Input: |
| 17 | + [ |
| 18 | + [ 1, 2, 3 ], |
| 19 | + [ 4, 5, 6 ], |
| 20 | + [ 7, 8, 9 ] |
| 21 | + ] |
| 22 | + Output: [1,2,3,6,9,8,7,4,5] |
| 23 | +Example 2: |
| 24 | +
|
| 25 | + Input: |
| 26 | + [ |
| 27 | + [1, 2, 3, 4], |
| 28 | + [5, 6, 7, 8], |
| 29 | + [9,10,11,12] |
| 30 | + ] |
| 31 | + Output: [1,2,3,4,8,12,11,10,9,5,6,7] |
| 32 | +``` |
| 33 | + |
| 34 | +## 参考答案 |
| 35 | + |
| 36 | +1. 剥洋葱,row->col->row->col 为一次; |
| 37 | +2. row->col、col->row 的切换都伴随读取的初始位置的变化; |
| 38 | +3. 结束条件是row头>row尾或者col顶>col底 |
| 39 | + |
| 40 | + |
| 41 | + |
| 42 | +时间复杂度O(m*n), 空间复杂度O(1) |
| 43 | + |
| 44 | +参考JavaScript代码: |
| 45 | + |
| 46 | +```js |
| 47 | +/** |
| 48 | + * @param {number[][]} matrix |
| 49 | + * @return {number[]} |
| 50 | + */ |
| 51 | +var spiralOrder = function(matrix) { |
| 52 | + if(matrix.length === 0) return []; |
| 53 | + let rowT = 0; // 行顶 |
| 54 | + let rowB = matrix.length - 1; // 行底 |
| 55 | + let colL = 0; // 列左 |
| 56 | + let colR = matrix[0].length - 1; // 列右 |
| 57 | + let result = []; |
| 58 | + // 顺序是行、列、行、列;每次切换,读取的初始位置都会变化1(+/- 1) |
| 59 | + while (colL <= colR && rowT <= rowB) { |
| 60 | + for (let a = colL; a <= colR; a++) { |
| 61 | + result.push(matrix[rowT][a]); |
| 62 | + } |
| 63 | + rowT++; |
| 64 | + for (let b = rowT; b <= rowB; b++) { |
| 65 | + result.push(matrix[b][colR]); |
| 66 | + } |
| 67 | + colR--; |
| 68 | + for (let c = colR; c >= colL && rowB >= rowT; c--) { |
| 69 | + result.push(matrix[rowB][c]); |
| 70 | + } |
| 71 | + rowB--; |
| 72 | + for (let d = rowB; d >= rowT && colR >= colL; d--) { |
| 73 | + result.push(matrix[d][colL]); |
| 74 | + } |
| 75 | + colL++; |
| 76 | + } |
| 77 | + return result; |
| 78 | +}; |
| 79 | +``` |
| 80 | + |
| 81 | +代码只有一个for循环的方式,操作方向 |
| 82 | +例如 |
| 83 | +> 1 2 3 4 5 |
| 84 | +> 6 7 8 9 10 |
| 85 | +> 11 12 13 14 15 |
| 86 | +> |
| 87 | +> 对上面矩阵遍历时的操作 |
| 88 | +> |
| 89 | +> 向右5次(算上从左侧第一次进入) |
| 90 | +> 向下2次 |
| 91 | +> 向左4次 |
| 92 | +> 向上1次 |
| 93 | +> 向右3次 |
| 94 | +> 向下0次 -- 结束 |
| 95 | +
|
| 96 | +方向有四个,right、down、left、up |
| 97 | +四个方向又分两类,水平(right,left)和垂直(down,up) |
| 98 | +而在两类方向上的移动最值是 水平n, 垂直m; |
| 99 | +在遍历过程中,根据`方向切换`来减小n/m从而缩小两类方向的移动最值直到结束 |
| 100 | +四个方向可以用二维数组来表示[ [0, 1], [1, 0], [0, -1], [-1, 0] ] |
| 101 | +两类方向各自的初始最大值是[n, m-1] |
| 102 | +当 n == 0 || m == 0 表示元素已经全部遍历完 |
| 103 | + |
| 104 | +这种写法省去了代码中的for循环,但是while循环次数却增多了;复杂度没有变化 |
| 105 | +时间复杂度O(m*n), 空间复杂度O(1) |
| 106 | + |
| 107 | +参考JavaScript代码: |
| 108 | + |
| 109 | +```js |
| 110 | +/** |
| 111 | + * @param {number[][]} matrix |
| 112 | + * @return {number[]} |
| 113 | + * 一个for循环,但while变多了 |
| 114 | + */ |
| 115 | +var spiralOrder = function(matrix) { |
| 116 | + if(matrix.length === 0) return []; |
| 117 | + let m = matrix.length; |
| 118 | + let n = matrix[0].length; |
| 119 | + let result = []; |
| 120 | + const dirs = [[0, 1], [1, 0], [0, -1], [-1, 0]] // 控制方向的数组 |
| 121 | + // 元素坐标row,col; |
| 122 | + let row = 0; |
| 123 | + let col = -1; |
| 124 | + let steps = [n, m-1] |
| 125 | + let dir = 0; // 初始方向 |
| 126 | + while(steps[dir%2]) { |
| 127 | + for(let i = 0; i < steps[dir%2]; i++) { |
| 128 | + // 方向的改变的效果,row/col能增能减 |
| 129 | + row += dirs[dir][0]; col += dirs[dir][1]; |
| 130 | + result.push(matrix[row][col]) |
| 131 | + } |
| 132 | + steps[dir%2]--; // 移动极值缩小 |
| 133 | + dir = (dir+1)%4; // 方向改变 |
| 134 | + } |
| 135 | + return result; |
| 136 | +}; |
| 137 | +``` |
| 138 | + |
| 139 | +## 优秀解答 |
| 140 | + |
| 141 | +> 暂缺 |
| 142 | +
|
| 143 | +## 参考 |
| 144 | +- @stellari [A concise C++ implementation based on Directions](https://leetcode.com/problems/spiral-matrix/discuss/20573/A-concise-C%2B%2B-implementation-based-on-Directions) |
0 commit comments