Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.
For example,
Given the following matrix:
[ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]
You should return [1,2,3,6,9,8,7,4,5]
.
题意就是螺旋式地输出一个数组。注意行数有 m 行,列数有 n 列,并不是正方形。
我的思路是找到其中的规律,总是按照 往右走->往下走->往左走->往上走 这样子循环往复的,而在水平方向走时,比如一开始往右走了3步,接下来水平方向往左走只能走2步(因为被往下走的那段占了),再之后往右走只能走1步。所以说 每往水平方向走一趟,能走的步数都要减一。竖直方向也是同理。
需要注意的是,水平方向初始能走的步数是列数,竖直方向能走的步数是行数。此外,刚开始的坐标位置应置于 (-1,0),因为一开始需要往右走 n 个格子(是先加方向再add list)。
另外,当任意一个方向上能走的步数变为 0 时,此时跳出while循环,还需要再按照下一个方向走一回,因为有可能另外一个方向上还没走完(详情见我的测试用例)。
package leetcode;
import java.util.ArrayList;
import java.util.List;
public class Spiral_Matrix_54 {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> list = new ArrayList<Integer>();
if(matrix.length==0||matrix[0].length==0){
return list;
}
int[][] direction = new int[][] { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 }// 右下左上
};
int m=matrix.length;
int n=matrix[0].length;
int dPointer=0;
int x=0;
int y=-1;
m--;
while(m!=0&&n!=0){
if(dPointer%2==0){//横着走,走的是列数
for(int i=0;i<n;i++){
x=x+direction[dPointer][0];
y=y+direction[dPointer][1];
list.add(matrix[x][y]);
}
n--;
}
else{//竖着走,走的是行数
for(int i=0;i<m;i++){
x=x+direction[dPointer][0];
y=y+direction[dPointer][1];
list.add(matrix[x][y]);
}
m--;
}
dPointer=(dPointer+1)%4;
}
if(dPointer%2==0){//横着走,走的是列数
for(int i=0;i<n;i++){
x=x+direction[dPointer][0];
y=y+direction[dPointer][1];
list.add(matrix[x][y]);
}
}
else{//竖着走,走的是行数
for(int i=0;i<m;i++){
x=x+direction[dPointer][0];
y=y+direction[dPointer][1];
list.add(matrix[x][y]);
}
}
return list;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Spiral_Matrix_54 s=new Spiral_Matrix_54();
int[][] matrix=new int[][]{
{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15}
};
List<Integer> list=s.spiralOrder(matrix);
for(int i:list){
System.out.print(i+" ");
}
System.out.println();
}
}
我的代码真是冗长啊。我发现可以优化我的代码,把while循环的判断条件改一下,使用一个计数器,来统计是否已经 add 了 m*n 个数,当个数达到 m*n 时,跳出循环。这样就不需要在 while 循环之后再走一遍方向了。
相比之下大神的解法就很机智。
先是往右走,并增加 rowBegin, 然后往下走并减小 colEnd, 之后往左走并减小 rowEnd, 最后往上走并增加 colBegin。需要注意的是,当往左走和往上走时,需要检查是否 rowBegin <= rowEnd 和 colBegin <= colEnd,以防止重复。
相当于每走完一边,就在那一边筑一堵墙。比如往右走,也就是在上边界走,走完后在上边界筑墙,即 rowBegin++。
public class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<Integer>();
if (matrix.length == 0) {
return res;
}
int rowBegin = 0;
int rowEnd = matrix.length-1;
int colBegin = 0;
int colEnd = matrix[0].length - 1;
while (rowBegin <= rowEnd && colBegin <= colEnd) {
// Traverse Right
for (int j = colBegin; j <= colEnd; j ++) {
res.add(matrix[rowBegin][j]);
}
rowBegin++;
// Traverse Down
for (int j = rowBegin; j <= rowEnd; j ++) {
res.add(matrix[j][colEnd]);
}
colEnd--;
if (rowBegin <= rowEnd) {
// Traverse Left
for (int j = colEnd; j >= colBegin; j --) {
res.add(matrix[rowEnd][j]);
}
}
rowEnd--;
if (colBegin <= colEnd) {
// Traver Up
for (int j = rowEnd; j >= rowBegin; j --) {
res.add(matrix[j][colBegin]);
}
}
colBegin ++;
}
return res;
}
}
这道题有solutions:
https://leetcode.com/problems/spiral-matrix/solution/
solutions的解法和大神的解法思路一样,就不赘述了。