题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
针对这道题目真是无力吐槽,虽然看起来逻辑很简单,但是实现起来的时候踩了无数的坑,从程序终止条件到循环开始条件都需要仔细地研究,对于很多边界条件也需要注意,最终导致程序相当混乱。
下面通过在代码中注释的方法来分析各种坑。
public class Solution {
public static ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> result = new ArrayList<Integer>();
if(matrix.length == 0) return null;
//下面是解决这个问题的主体思路,确定左上角的点和右下角的点,这样便可以确定需要循环的矩形
//startX,初始列号;startY,初始行号;endX,终止列号;endY,终止行号.
int startX = 0, startY = 0, endX = matrix[0].length - startX - 1, endY = matrix.length - startY - 1;
//下面是解决问题的难点,即怎样判定所有的矩形已经得到遍历。我们发现,在5*5的矩阵中,各矩形左上角的点
// 依次为(0,0),(1,1),(2,2)。2 * 2 < 5, 2 * 2 < 5;同样的3*5的矩阵中,各矩形左上角的点依次为
//(0,0),(1,1)。依然满足1 * 1 < 3, 1 * 1 < 5。所以可以通过左上角的点的坐标来判断程序是否中止。这是很重要的一个点,
//当初就卡在了这里。
while(startX * 2 < matrix[0].length && startY * 2 < matrix.length) {
//从左到右扫描,每一种矩形都有这一步,所以不需要加if判断
//之前使用惯了i++,但是这样会导致循环完之后数组溢出,故采用++i
for(int i = startX; i <= endX; ++i) {
result.add(matrix[startY][i]);
}
//从上到下扫描,需要保证endY > startY,没有等号
if(startY < endY) {
System.out.println(startY + " " + endY);
//需要在startY的基础上加一,不然会让同一个数被扫描两遍
//有等号,因为要保证所有数据均被扫描到
for(int i = startY + 1; i <=endY; ++i) {
result.add(matrix[i][endX]);
}
}
//从右到左扫描,需要保证矩形右下角的点在左上角点的右方和下方(缺一不可)
if(startX < endX && startY < endY) {
for(int i = endX - 1; i >= startX; --i) {
result.add(matrix[endY][i]);
}
}
/*从下到上扫描,需要保证矩形右下角的点在左上角点的右方和下方(缺一不可),
并且,endY至少比startY大2。*/
if(endY > (startY + 1) && startX < endX) {
for(int i = endY - 1; i > startY; --i) {
result.add(matrix[i][startX]);
}
}
//需要注意记得更新左上角和右下角的点
startX++;
startY++;
endX--;
endY--;
}
return result;
}
}
另外还有另外一种方法来计算程序是否应停止。
int row = matrix.length; //行数
int collor = matrix[0].length; //列数
int circle = ((row < collor ? row : collor) + 1) / 2 //圈数
通过圈数即可判断程序是否应该停止。
网友评论