给定一个包含 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]
思路1:模拟
绘制螺旋轨迹路径,我们发现当路径超出界限或者进入之前访问过的单元格时,会顺时针旋转方向。
算法
假设数组有R行C列,seen[r][c] 表示第 r 行第 c 列的单元格之前已经被访问过了。当前所在位置为(r, c),前进方向是di。我们希望访问所有 R x C 个单元格。
当我们遍历整个矩阵,下一步候选移动位置是(cr, cc)。如果这个候选位置在矩阵范围内并且没有被访问过,那么它将会变成下一步移动的位置;否则,我们将前进方向顺时针旋转之后再计算下一步的移动位置。
题解:
class Solution1{
public List<Integer>spiralOrder(int[][] matrix){
//定义一个链表
List ans = new ArrayList();
//矩阵为空则返回空链表
if(matrix.length == 0)
return ans;
//获取矩阵维度
int R = matrix.length, C = matrix[0].length;
//定义同样维度的布尔型矩阵,用于标识矩阵元素是否被访问过
boolean[][] seen = new boolean[R][C];
//
int[] dr = {0,1,0,-1};
int[] dc = {1,0,-1,0};
//前进方向di,当前所在位置[r][c]
int r = 0,c = 0,di = 0;
//
for(int i=0;i<R*C;i++) {
ans.add(matrix[r][c]);
//矩阵中访问的元素位置标为true
seen[r][c] = true;
//候选移动位置是 (cr, cc)
int cr = r + dr[di];
int cc = c + dc[di]; //boolean类型定义的数组,默认值是false
if(cr >= 0 && cr < R && cc >= 0 && cc < C && !seen[cr][cc]){
r = cr; //if括号内,当且仅当不超出边界且未被访问过才为真
c = cc;
}else {
//如果候选移动位置超出边界或被访问过,则顺时针旋转方向
di = (di + 1) % 4;
r += dr[di];
c += dc[di];
}
}
return ans;
}
}
复杂度分析
时间复杂度: O(N),其中 N 是输入矩阵所有元素的个数。因为我们将矩阵中的每个元素都添加进答案里。
空间复杂度: O(N),需要两个矩阵 seen 和 ans 存储所需信息。
思路2:按层模拟
答案是最外层所有元素按照顺时针顺序输出,其次是次外层,以此类推。
对于每层,我们从左上方开始以顺时针的顺序遍历所有元素,假设当前层左上角坐标是(r1, c1),右下角坐标是(r2, c2)。
首先,遍历上方的所有元素(r1, c),按照 c = c1,...,c2 的顺序。然后遍历右侧的所有元素(r, c2),按照 r = r1+1,...,r2 的顺序。如果这一层有四条边(也就是r1 < r2 并且c1 < c2 ),我们以下图所示的方式遍历下方的元素和左侧的元素。
class Solution2{
public List<Integer>spiralOrder(int[][] matrix){
List ans = new ArrayList();
if(matrix.length == 0)
return ans;
int r1 = 0,r2 = matrix.length - 1;
int c1 = 0,c2 = matrix[0].length - 1;
while(r1 <= r2 && c1 <= c2) {
for(int c = c1; c <= c2; c++)
ans.add(matrix[r1][c]);
for(int r = r1 + 1; r <= r2 ;r++)
ans.add(matrix[r][c2]);
if(r1 < r2 && c1 < c2) {
for(int c = c2 - 1;c > c1;c--)
ans.add(matrix[r2][c]);
for(int r = r2;r > r1;r--)
ans.add(matrix[r][c1]);
}
r1++;
r2--;
c1++;
c2--;
}
return ans;
}
}
复杂度分析
时间复杂度: O(N),其中 N 是输入矩阵所有元素的个数。因为我们将矩阵中的每个元素都添加进答案里。
空间复杂度: O(N),需要矩阵 ans 存储信息。
(本人倾向于第一种)