输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 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]
方法一:模拟
可以模拟打印矩阵的路径。初始位置是矩阵的左上角,初始方向是向右,当路径超出界限或者进入之前访问过的位置时,顺时针旋转,进入下一个方向。
判断路径是否进入之前访问过的位置需要使用一个与输入矩阵大小相同的辅助矩阵 visited,其中的每个元素表示该位置是否被访问过。当一个元素被访问时,将 visited 中的对应位置的元素设为已访问。
如何判断路径是否结束?由于矩阵中的每个元素都被访问一次,因此路径的长度即为矩阵中的元素数量,当路径的长度达到矩阵中的元素数量时即为完整路径,将该路径返回。
class Solution {
public int[] spiralOrder(int[][] matrix) {
if(matrix.length == 0){
return new int[0];
}
int row = matrix.length;//行的边界
int col = matrix[0].length;//列的边界
boolean[][] isVisited = new boolean[row][col];//判断是否遍历
int n = row*col;//数字的个数
int[] nums = new int[n];
int[][] directions = new int[][]{{0,1},{1,0},{0,-1},{-1,0}};
int x = 0;
int y = 0;//初始索引位置
int directionsIndex = 0;//初始方向索引
for(int i = 0;i < n;i++){
nums[i] = matrix[x][y];
isVisited[x][y] = true;//设置成已经访问
int nextX = x+directions[directionsIndex][0],nextY=y+directions[directionsIndex][1];//按照此方向的下一个索引
if(nextX < 0 || nextX >= row || nextY < 0 || nextY >= col || isVisited[nextX][nextY]){
//若下一节点的索引值越界或者已经访问,则调整方向
directionsIndex = (directionsIndex + 1 ) % 4;
}
x = x + directions[directionsIndex][0];
y = y + directions[directionsIndex][1];//下一个未访问的节点
}
return nums;
}
}
//时间复杂度:O(mn)
//空间复杂度:O(mn) 用于存储是否访问矩阵isVisited[][]
方法二:按层模拟
可以将矩阵看成若干层,首先打印最外层的元素,其次打印次外层的元素,直到打印最内层的元素。
定义矩阵的第 k 层是到最近边界距离为 k 的所有顶点。例如,下图矩阵最外层元素都是第 1层,次外层元素都是第 2 层,剩下的元素都是第 3 层。
[[1, 1, 1, 1, 1, 1, 1],
[1, 2, 2, 2, 2, 2, 1],
[1, 2, 3, 3, 3, 2, 1],
[1, 2, 2, 2, 2, 2, 1],
[1, 1, 1, 1, 1, 1, 1]]
class Solution {
//按层模拟
public int[] spiralOrder(int[][] matrix) {
if(matrix.length == 0){
return new int[0];
}
int top = 0;
int bottom = matrix.length - 1;
int left = 0;
int right = matrix[0].length - 1;//第一层的上下左右边界
int[] nums = new int[matrix.length * matrix[0].length];//创建返回数组
int count = 0;//统计次数
while(left <= right && top <= bottom){//直到4个边界重合
for(int col = left;col <= right;col++){//添加最上层
nums[count++] = matrix[top][col];
}
for(int row = top+1;row <= bottom;row++){//添加最右侧
nums[count++] = matrix[row][right];
}
if(left < right && top < bottom){//这个条件必须加,因为可能不需要添加下层和左侧,如上述的第3层 就没有最下层,和最左侧
for(int col = right - 1;col >=left;col--){//添加最下层
nums[count++] = matrix[bottom][col];
}
for(int row = bottom -1;row >= top+1;row--){//添加最左侧
nums[count++] = matrix[row][left];
}
}
top++;
left++;
right--;
bottom--;
}
return nums;
}
}
//时间复杂度:O(mn)
//空间复杂度:O(1)