一、需求
- 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
二、模拟法1
2.1 思路分析
- 空值处理:当矩阵为空时,返回的是只有元素0的矩阵;
- 初始化:设矩阵的左、右、上、下边界为left、right、top、bottom,用于打印的结果列表res;
- 循环打印:" 从左向右、从上到下、从右向左、从下到上 " 依次循环,每个方向的打印都要做三件事:
- 根据边界,将元素按顺序添加至列表res尾部;
- 当解决一条边界后(比如打印完了从左到右的元素),边界要向内收缩(这时候这条边界就不要了,上边界top-1);
- 判断是否打印完毕,即边界是否相遇,打印完毕则退出循环。
2.2 代码实现
class Solution {
public int[] spiralOrder(int[][] matrix) {
if(matrix.length == 0) return new int[0];
int top = 0;
int down = matrix.length - 1;
int left = 0;
int right = matrix[0].length - 1;
int[] res = new int[(down+1)*(right+1)];
int index = 0;
while(true) {
for(int i = left; i <= right; i++) {
res[index++] = matrix[top][i];
}
if(++top > down) break;
for(int i = top; i <= down; i++) {
res[index++] = matrix[i][right];
}
if(--right < left) break;
for(int i = right; i >= left; i--) {
res[index++] = matrix[down][i];
}
if(--down < top) break;
for(int i = down; i >= top; i--) {
res[index++] = matrix[i][left];
}
if(++left > right) break;
}
return res;
}
}
2.3 复杂度分析
- 需要遍历矩阵的所有元素,时间复杂度为O(MN);
- 空间复杂度为O(1),返回结果数组不计入空间复杂度;
三、模拟法2(推荐)
3.1 思路分析
3.2 代码实现
class Solution {
public int[] spiralOrder(int[][] matrix) {
if(matrix.length == 0) return new int[0];
int m = matrix.length;
int n = matrix[0].length;
boolean[][] visit = new boolean[m][n];
int[] res = new int[m * n];
int[] rowArr = {-1, 0, 1, 0};
int[] colArr = {0, 1, 0, -1};
int row = 0, col = 0, d = 1;
for(int i = 0; i < res.length; i++) {
res[i] = matrix[row][col];
visit[row][col] = true;
//获取下个位置的坐标
int nextRow = row + rowArr[d];
int nextCol = col + colArr[d];
//若下一个坐标的位置越界则旋转90°
if(nextRow < 0 || nextRow >= m || nextCol < 0 || nextCol >= n || visit
[nextRow][nextCol]) {
d = (d + 1) % 4;
}
//在当前坐标的基础上移动到下一个非越界的位置
row = row + rowArr[d];
col = col + colArr[d];
}
return res;
}
}
3.3 复杂度分析
- 时间复杂度为O(MN),res存储元素需要遍历MN次;
- 空间复杂度为O(MN),visit数组消耗O(MN)的额外空间;
四、学习地址
作者:LeetCode-Solution
作者:Krahets