题目
给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。
示例 1:
输入:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
输出: [1,2,3,6,9,8,7,4,5]
示例 2:
输入:
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/spiral-matrix
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
第一种解法
思路:
顺时针旋转得话就应该先是从左到右,从上到下,从右到左,从下到上
问题来了怎么才能实现这个方法呢
1.访问过的会再访问一次怎么区分呢
💡 可以设置标记数组,和已知数组下标一样,用来标记是否访问过
2.方向怎么改变呢,什么时候变呢
💡 可以来一个二维数组专门用来改变方向的
从左到右 行不变 列+1 {0,1}
从上到下 行+1 列不变 {1,0}
从右到左 行不变 列-1 {0,-1}
从下到上 行-1 列不变 {-1,0}
改变的条件:下边越界或者已经标记过的时候就该换方向了
代码:
public static List<Integer> spiralOrder(int[][] matrix) {
List<Integer> order = new ArrayList<>();
int rows = matrix.length, columns = matrix[0].length;
if (matrix == null || rows == 0 || columns == 0) {
return order;
}
// 定义标记数组
boolean[][] visited = new boolean[rows][columns];
// 定义遍历的方向
int[][] directon = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
// 定义方向的初始值
int directionIndex = 0;
int row = 0, col = 0;
int total = rows * columns;
for (int i = 0; i < total; i++) {
// 将该元素加入到order中
order.add(matrix[row][col]);
// 标记
visited[row][col] = true;
// 定位下一行,下一列
int nextRow = row + directon[directionIndex][0];
int nextCol = col + directon[directionIndex][1];
// 判断是否符合标准,越界或者标记过
if (nextRow >= rows || nextRow < 0 || nextCol >= columns || nextCol < 0
|| visited[nextRow][nextCol] == true) {
// if (nextRow >= rows || nextCol >= columns || visited[nextRow][nextCol] ||
// nextCol < 0 || nextRow < 0) {
// 原来的方向行不通了,该换个方向了
// direction 一共有4行即4个方向,模4防止下标越界
directionIndex = (directionIndex + 1) % 4;
}
row = row + directon[directionIndex][0];
col = col + directon[directionIndex][1];
}
return order;
}
复杂度分析:
时间复杂度:O(mn),m 和 n 是输入矩阵的行数和列数。
空间复杂度:O(mn),需要创建一个大小和matrix相同的的二维数组visited用来记录每个位置是否被访问过。
第二种解法:按层模拟
思路:
按层模拟遍历顺序 : 上侧(从左到右)
右侧(从上到下)
下侧(从右到左)
左侧(从下到上)
怎么实现呢?
💡 可以设置坐标,用坐标来表示呀四个角的坐标分别是:
左上角:(top,left)
右上角:(top,right)
右下角:(bottom,right)
左下角:(bottom,left)
遍历顺序就应该是:
上侧 : (top,left)-->(top,right)
右侧 : (top+1,right) -->(bottom,right)
下侧 : (bottom,right-1) -->(bottom,left)
左侧 : (bottom,left)-->(top+1,left)
代码:
public static List<Integer> spiralOrder(int[][] matrix) {
List<Integer> order = new ArrayList<>();
int rows = matrix.length, cols = matrix[0].length;
int top = 0, bottom = rows - 1, left = 0, right = cols - 1;
if (matrix == null || rows == 0 || cols == 0) {
return order;
}
while (left <= right && top <= bottom) {
// 遍历上侧
for (int colsh = left; colsh <= right; colsh++) {
order.add(matrix[top][colsh]);
}
// 遍历右侧
for (int row = top + 1; row <= bottom; row++) {
order.add(matrix[row][right]);
}
if (left < right && top < bottom) {
// 遍历下侧
for (int colx = right - 1; colx > left; colx--) {
order.add(matrix[bottom][colx]);
}
// 遍历左侧
for (int rowz = bottom; rowz > top; rowz--) {
order.add(matrix[rowz][left]);
}
}
top++;
left++;
right--;
bottom--;
}
return order;
复杂度分析:
时间复杂度:O(mn),m 和 n 是输入矩阵的行数和列数
空间复杂度:O(1)。除了order以外,空间复杂度是常数。