🚩传送门:牛客题目
题目
给你一个 行
列的矩阵
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2,3,6,9,8,7,4,5]
解题思路:模拟
可以模拟螺旋矩阵的路径。
初始位置是矩阵的左上角,初始方向是向右,当路径超出界限或者进入之前访问过的位置时,顺时针旋转,进入下一个方向。
如何判断路径是否进入之前访问过的位置?
需要使用一个与输入矩阵大小相同的辅助矩阵 ,其中的每个元素表示该位置是否被访问过。当一个元素被访问时,将
中的对应位置的元素设为已访问。
如何判断路径是否结束?
由于矩阵中的每个元素都被访问一次,因此路径的长度即为矩阵中的元素数量,当路径的长度达到矩阵中的元素数量时即为完整路径,将该路径返回。
复杂度分析
时间复杂度: ,其中
和
分别是输入矩阵的行数和列数。
- 矩阵中的每个元素都要被访问一次。
空间复杂度:
- 需要创建一个大小为的矩阵  记录每个位置是否被访问过。
我的代码
package array.array66;
import java.util.ArrayList;
import java.util.List;
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<Integer>();
//1. 检查非法越界
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return res;
}
//2. 记录行、列数
int rows = matrix.length, columns = matrix[0].length;
//3. 创建标记数组
boolean[][] visited = new boolean[rows][columns];
//4. 总数量
int total = rows * columns;
//5. 左上角起始点(0,0)
int row = 0, column = 0;
//6. 方向数组
int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int directionIndex = 0;
for (int i = 0; i < total; i++) {
res.add(matrix[row][column]); //集合添加当前元素
visited[row][column] = true; //当前元素标记访问
int nextRow = row + directions[directionIndex][0], nextColumn = column + directions[directionIndex][1];
//7. 新坐标越界或者当前坐标已被标记访问,转入下一个方向
if (nextRow < 0 || nextRow >= rows || nextColumn < 0 || nextColumn >= columns || visited[nextRow][nextColumn]) {
directionIndex = (directionIndex + 1) % 4;
}
row += directions[directionIndex][0];
column += directions[directionIndex][1];
}
return res;
}
}
解题思路:按层模拟
脱衣服一样,一层层脱
可以将矩阵看成若干层,首先输出最外层的元素,其次输出次外层的元素,直到输出最内层的元素。
对于每层,从左上方开始以顺时针的顺序遍历所有元素。假设当前层的左上角位于 ,右下角位于
,按照如下顺序遍历当前层的元素。
- _从左到右遍历上侧元素,依次为 __ 到__ 。_
- _从上到下遍历右侧元素,依次为__到 __。_
- _从右到左遍历下侧元素,依次为__到 __ _
不能与 step1 同行。
- _从下到上遍历左侧元素,依次为__到 _
不能与 step2 同列。
遍历完当前层的元素后,将 增加
,将
和
分别减少
,进入下一层继续遍历,直到遍历完所有元素。
复杂度分析
时间复杂度: ,其中 m 和 n 分别是输入矩阵的行数和列数。
- 矩阵中的每个元素都要被访问一次。
空间复杂度: ,除了输出数组以外,空间复杂度是常数。
我的代码
public class Solution {
public ArrayList<Integer> travlaMatrix(int[][] matrix, int level, int x, int y){ //x坐标长度,纵坐标长度
ArrayList<Integer> res=new ArrayList<>();
while(x>0&&y>0){
for(int i=0;i<x;i++)
res.add(matrix[level][level+i]);
for(int i=1;i<y-1;i++)
res.add(matrix[level+i][level+x-1]);
for(int i=x-1;i>=0&&y-1>0;i--) //不能和第1个for同行
res.add(matrix[level+y-1][level+i]);
for(int i=y-2;i>0&&x-1>0;i--) //不能和第2个for同列
res.add(matrix[level+i][level]);
level++;x-=2;y-=2;
}
return res;
}
public ArrayList<Integer> spiralOrder(int[][] matrix) {
ArrayList<Integer> res=new ArrayList<>();
if(matrix.length==0)return res;
res=travlaMatrix(matrix,0,matrix[0].length,matrix.length);
return res;
}
}