大家好,我是吴师兄。
金三银四快要过去了,大家拿到了理想的 Offer 吗?
不管有没有,平时还是得把八股文等基础知识学习好。
今天分享的题目是剑指 Offer 29. 顺时针打印矩阵。
题目描述如下:
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 1:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
直接来看分析。
对于一个二维矩阵来说,它包含了如下的边界与打印顺序:
在打印的过程中,矩阵的可打印区间在不断的发生变化:
每当 top、right、bottom、left 发生挪动之后,需要判断它们挪动之后的区间是否还存在。
顺着这个思路,五分钟写完代码:
// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 代码有看不懂的地方一定要私聊咨询吴师兄呀
class Solution {
public int[] spiralOrder(int[][] matrix) {
// 特殊情况,边界处理,比如 matrix = [],无法获取 matrix[0]
if (matrix.length == 0) {
return new int[0];
}
// 设置一个一维数组 res 用来记录二维数组 matrix 中的顺时针打印的结果
int[] res = new int[matrix.length * matrix[0].length];
// 在打印的过程中,不断的缩小着打印的区间
// 每当把从左到右把一行打印完毕之后,整个矩阵就在顶部少了一层,后续打印不需要再去处理它们
// 每当把从上到下把一列打印完毕之后,整个矩阵就在右部少了一列,后续打印不需要再去处理它们
// 每当把从右到左把一行打印完毕之后,整个矩阵就在底部少了一层,后续打印不需要再去处理它们
// 每当把从下到上把一列打印完毕之后,整个矩阵就在左部少了一列,后续打印不需要再去处理它们
// 因此,设置四个变量,用来记录打印的区间变化
// top 表示顶部所在的层数位置,一开始在第 0 层
int top = 0 ;
// bottom 表示底部所在的层数位置,一开始在第 matrix.length - 1 层
int bottom = matrix.length - 1 ;
// left 表示左部所在的列数位置,一开始在第 0 列
int left = 0 ;
// right 表示右部所在的列数位置,一开始在第 matrix[0].length - 1 列
int right = matrix[0].length - 1;
// 顺时针打印矩阵过程中,填充 res 数组,从索引位置 0 的地方开始填充
int index = 0;
// 使用一个 while 循环进行打印,只要打印区间中还有值就一直打印
// 直到出现边界越界,即打印区间不存在元素了,跳出循环
while (true) {
// 1、从左到右,打印这一行
// 此时,边界从 left 到 right
for (int i = left; i <= right; i++) {
// 将当前元素填充到 res 中
// 此时,一直都是在 top 这一层
res[index] = matrix[top][i];
// index 的元素填充完毕之后,开始填充下一个元素
index++;
}
// 经过上面这个循环之后,此时,顶部这一层的所有元素已经打印完毕
// 整个打印区间需要删除这一行了,因此,将 top 的层数向下挪
top += 1;
// 如果此时发现顶部位置越过了底部位置,说明整个打印区间已经没有元素了
// 跳出循环即可
if ( top > bottom ) {
break;
}
// 2、从上到下,打印这一列
// 此时,边界从 top 到 bottom
for (int i = top; i <= bottom; i++) {
// 将当前元素填充到 res 中
// 此时,一直都是在 right 这一列
res[index] = matrix[i][right];
// index 的元素填充完毕之后,开始填充下一个元素
index++;
}
// 经过上面这个循环之后,此时,右部这一列的所有元素已经打印完毕
// 整个打印区间需要删除这一列了,因此,将 right 的层数向左挪
right -= 1;
// 如果此时发现右部位置越过了左部位置,说明整个打印区间已经没有元素了
// 跳出循环即可
if ( right < left ) {
break;
}
// 3、从右到左,打印这一行
// 此时,边界从 right 到 left
for (int i = right; i >= left; i--) {
// 将当前元素填充到 res 中
// 此时,一直都是在 bottom 这一层
res[index] = matrix[bottom][i];
// index 的元素填充完毕之后,开始填充下一个元素
index++;
}
// 经过上面这个循环之后,此时,底部这一层的所有元素已经打印完毕
// 整个打印区间需要删除这一行了,因此,将 bottom 的层数向上挪
bottom -= 1;
// 如果此时发现顶部位置越过了底部位置,说明整个打印区间已经没有元素了
// 跳出循环即可
if ( bottom < top ) {
break;
}
// 4、从下到上,打印这一列
// 此时,边界从 bottom 到 top
for (int i = bottom; i >= top; i--) {
// 将当前元素填充到 res 中
// 此时,一直都是在 left 这一列
res[index] = matrix[i][left];
// index 的元素填充完毕之后,开始填充下一个元素
index++;
}
// 经过上面这个循环之后,此时,左部这一列的所有元素已经打印完毕
// 整个打印区间需要删除这一列了,因此,将 left 的层数向右挪
left += 1;
// 如果此时发现右部位置越过了左部位置,说明整个打印区间已经没有元素了
// 跳出循环即可
if ( left > right ) {
break;
}
}
// 最后,返回结果即可
return res;
}
}