1. 螺旋矩阵1
(1)按圈模拟
(用的叶姐图)——记录觉得特别好的题解
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
//特判为空情况,防止出问题
if (matrix == null || m == 0 || n == 0)
return new int[0];
List<Integer> ans = new ArrayList<>();
circle(matrix, 0, 0, m -1, n - 1, ans);
return ans;
}
// 遍历 以 (x1, y1) 作为左上角,(x2, y2) 作为右下角形成的「圈」
public void circle(int[][] matrix, int x1, int y1, int x2, int y2, List<Integer> ans) {
if (x2 < x1 || y2 < y1)
return;
// 只有一行时,按「行」遍历, 注意这里要遍历到最后一位 i <= y2, matrix[x1][i]
if (x1 == x2) {
for (int i = y1; i <= y2; i++) {
ans.add(matrix[x1][i]);
}
return;
}
// 只有一列时,按「列」遍历,同理 i <= x2, matrix[i][y2]
if (y1 == y2) {
for (int i = x1; i <= x2; i++) {
ans.add(matrix[i][y2]);
}
return;
}
// 遍历当前 圈
for (int i = y1; i < y2; i++) {
ans.add(matrix[x1][i]);
}
for (int i = x1; i < x2; i++) {
ans.add(matrix[i][y2]);
}
for (int i = y2; i > y1; i--) {
ans.add(matrix[x2][i]);
}
for (int i = x2; i > x1; i--) {
ans.add(matrix[i][y1]);
}
// 往里收一圈,继续遍历
circle(matrix, x1 + 1, y1 + 1, x2 - 1, y2 - 1, ans);
}
}
(2)按层模拟
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> list = new ArrayList<Integer>();
if (matrix == null || matrix.length == 0 || matrix[0].length == 0)
return list;
int m = matrix.length;
int n = matrix[0].length;
int i = 0;
//统计矩阵从外向内的层数,如果矩阵非空,那么它的层数至少为1层
int count = (Math.min(m, n)+1)/2;
//从外部向内部遍历,逐层打印数据
while (i < count) {
for (int j = i; j < n-i; j++) {
list.add(matrix[i][j]);
}
for (int j = i+1; j < m-i; j++) {
list.add(matrix[j][(n-1)-i]);
}
for (int j = (n-1)-(i+1); j >= i && (m-1-i != i); j--) {
list.add(matrix[(m-1)-i][j]);
}
for (int j = (m-1)-(i+1); j >= i+1 && (n-1-i) != i; j--) {
list.add(matrix[j][i]);
}
i++;
}
return list;
}
}
(3)直接遍历矩阵
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> ans = new ArrayList<>();
if (matrix == null || matrix.length == 0 || matrix[0].length == 0)
return ans;
// 左列,右列,上行,下行
int left = 0;
int right = matrix[0].length-1;
int top = 0;
int down = matrix.length-1;
while (true) {
//左 -> 右
for (int i = left; i <= right; ++i) {
ans.add(matrix[top][i]);
}
top++;
if (top > down)
break;
//右上 -> 右下
for (int i = top; i <= down; ++i) {
ans.add(matrix[i][right]);
}
right--;
if (left > right)
break;
//右 -> 左
for (int i = right; i >= left; --i) {
ans.add(matrix[down][i]);
}
down--;
if (top > down)
break;
//左下 -> 左上
for (int i = down; i >= top; --i) {
ans.add(matrix[i][left]);
}
left++;
if (left > right)
break;
}
return ans;
}
}
2. 螺旋矩阵2
(1)按圈模拟
class Solution {
public int[][] generateMatrix(int n) {
int[][] ans = new int[n][n];
circle(0, 0, n - 1, n - 1, 1, ans);
return ans;
}
void circle(int x1, int y1, int x2, int y2, int start, int[][] ans) {
if (x2 < x1 || y2 < y1) return ;
if (x1 == x2) {
ans[x1][y1] = start;
return;
}
if (y1 == y2) {
ans[x1][y1] = start;
return;
}
int val = start; //从1开始
// 从左往右,
for (int i = y1; i < y2; i++)
ans[x1][i] = val++;
// 从右往下
for (int i = x1; i < x2; i++)
ans[i][y2] = val++;
// 从右往左
for (int i = y2; i > y1; i--)
ans[x2][i] = val++;
//从下往上
for (int i = x2; i > x1; i--)
ans[i][y1] = val++;
circle(x1 + 1, y1 + 1, x2 - 1, y2 - 1, val, ans);
}
}
(2)按照方向模拟
class Solution {
public int[][] generateMatrix(int n) {
int[][] ans = new int[n][n];
// 左列,右列,上行,下行
int left = 0;
int right = n-1;
int top = 0;
int down = n-1;
int val = 1;
while (true) {
//左 -> 右
for (int i = left; i <= right; ++i) {
ans[top][i] = val++;
}
top++;
if (top > down)
break;
//右上 -> 右下
for (int i = top; i <= down; ++i) {
ans[i][right] = val++;
}
right--;
if (left > right)
break;
//右 -> 左
for (int i = right; i >= left; --i) {
ans[down][i] = val++;
}
down--;
if (top > down)
break;
//左下 -> 左上
for (int i = down; i >= top; --i) {
ans[i][left] = val++;
}
left++;
if (left > right)
break;
}
return ans;
}
}
化简一下更好看:
class Solution {
public int[][] generateMatrix(int n) {
int[][] ans = new int[n][n];
// 定义四个方向
int[][] dirs = new int[][]{{0,1},{1,0},{0,-1},{-1,0}};
for (int x = 0, y = 0, d = 0, i = 1; i <= n * n; i++) {
ans[x][y] = i;
// 下一步要到达的位置
int nexX = x + dirs[d][0];
int nexY = y + dirs[d][1];
// 如果下一步发生「溢出」或者已经访问过(说明四个方向已经走过一次)
if (nexX < 0 || nexX >= n || nexY < 0 || nexY >= n || ans[nexX][nexY] != 0) {
d = (d + 1) % 4;
nexX = x + dirs[d][0];
nexY = y + dirs[d][1];
}
x = nexX;
y = nexY;
}
return ans;
}
}