题目
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 :
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
思路
数组的顺时针
①从左到右
②
上 从
至 上
下 到
从 下
④
左至右从 ③
我自己想到的思路是:
- 建立一个和原数组一样的boolean[][]数组,但访问过的元素置为true。
- 按照顺时针的顺序,将所有的元素访问完成。如果访问过,就不再访问了。
使用额外空间的解法
使用一个boolean[][] 二维数组,存储已经访问过的位置
这种想法的来源是,之前做过的一题 面试题 13 机器人的运动范围,记录曾经访问过的路径,确保不会再访问。
代码:
class Solution {
public int[] spiralOrder(int[][] matrix) {
// 取出异常的输入
if(matrix.length == 0 || matrix[0].length == 0) return new int[0];
// 建立一个boolean数组
boolean[][] visited = new boolean[matrix.length][matrix[0].length];
int[] ret = new int[matrix.length*matrix[0].length];
int index = 0;
visited[0][0] = true;
ret[index++] = matrix[0][0];
// 从 [0][0]开始遍历
for (int i=0; i<matrix.length; ){
for (int j=0; j<matrix[0].length; ){
// 先右
while(j+1<matrix[0].length && !visited[i][j+1]){
// 没有访问过
j++;
visited[i][j] = true;
ret[index++] = matrix[i][j];
}
// 否则下
while(i+1<matrix.length && !visited[i+1][j]){
i++;
visited[i][j] = true;
ret[index++] = matrix[i][j];
}
// 否则左
while(j-1>=0 && !visited[i][j-1]){
j--;
visited[i][j] = true;
ret[index++] = matrix[i][j];
}
// 否则上
while(i-1>=0 && !visited[i-1][j]){
i--;
visited[i][j] = true;
ret[index++] = matrix[i][j];
}
// 都不满足,跳出循环
if(index == ret.length){
return ret;
}
}
}
return ret;
}
}
更快的解法
- 找四个标志,分别记录矩阵逻辑上的上下左右四个边界
- 每次遍历往一行或者一列的时候,更新逻辑上的边界
代码:
class Solution {
public int[] spiralOrder(int[][] matrix) {
// 去除异常输入
if(matrix.length == 0) return new int[0];
// 建立矩阵的四个边界
int l = 0; // 左边界 left
int r = matrix[0].length-1; // 右边界 right
int t = 0; // 上边界 top
int b = matrix.length-1; // 下边界 bottom
// 矩阵的元素个数
int size = matrix.length*matrix[0].length;
int[] ret = new int[size]; // 返回值
int x = 0; // 数组下标(重要)
while(x < size){
// 保存所有的 left->right
for(int i=l; i<=r; i++) ret[x++] = matrix[t][i];
// 最上边一行完毕,上边界下移一位
if(++t>b) break;
// 保存所有的 top->bottom
for(int i=t; i<=b; i++) ret[x++] = matrix[i][r];
// 最右边一列输出完毕,右边界左移一位
if(--r<l) break;
// 保存所有的 left->right
for(int i=r; i>=l; i--) ret[x++] = matrix[b][i];
// 最下边一行输出完毕,下边界上移一位
if(--b<t) break;
// 保存所有的 bottom->top
for(int i=b; i>=t; i--) ret[x++] = matrix[i][l];
// 最左边一列输出完毕,左边界右移一位
if(++l>r) break;
}
return ret;
}
}
总结:
- 如果需要定义一个变量作为下标的话,可以尽量使用单词的首字母作为变量名。例如:left - l,right - r
- 比较重要的语句
这一句可以if(++t>b) break;
阻止
去访问,已经访问过了的元素。