题目
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 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.
解析
预备知识
我们需要对顺时针打印矩阵进行建模,也就是可以用一种规律描述这个问题。还是画图来吧,假设有4 X 4矩阵,顺时针的轨迹为:
假设有4 X 3矩阵,顺时针的轨迹为:
假设有3 X 4矩阵,顺时针的轨迹为:
假设有1 X 4矩阵,顺时针轨迹为:
假设有4 X 1矩阵,顺时针轨迹为:
通过以上我们可以发现其实矩阵的顺时针轨迹可以划分为几个圈。也就说我们可以从外到内一圈一圈的打印。所以现在问题转化为给定一个矩阵,如何判断出该打印几圈,通过以上画图,我们发现圈数的确定取决于矩阵的最短边。且每一圈的左上角顶点必为上一圈的顶点的坐标各加一。想象一下就明白了,我们是从外圈到内圈打,左上角坐标必然比上一多1嘛。
知道了以上,我们得出圈数为(最短边 + 1) / 2。因为圈的左上角顶点走到中间结束,加1的目的是为了处理奇数情况,奇数情况最后一圈为1行或1列。
因为从外圈到内圈结束有2种情况,当最短边为偶数时,最后一圈为2行n列或n行2列;当最短边为奇数时,最后一圈为1行n列或者n行1列。
思路一
我们通过预备知识已经知道了如何确定圈数,那么接下来着重考虑如何打印每一圈。
我们可以按各边的顺序依次打印,每一圈的走上角和右下角的坐标都知道了,那么这个圈也就确定了。分4个边打印即可。
左上角的坐标为(i, i), 我们是从外圈到内圈打,左上角坐标必然比上一多1嘛。
相反,右下角的坐标为(行总数-i,列总数-i)。我们是从外圈到内圈打,右上角坐标必然比上一少1嘛。
i为圈数。
但是需要注意两点:
1. 当打印下边的时候,要看看右下角的横坐标是否大于左上角,避免圈是一行的时候,重复打印。
2. 当打印左边的时候,要看看右下角的纵坐标是否大于左上角,避免圈是一列的时候,重复打印。
/**
* 1.确定圈数
* 2.打印每一圈
* @param matrix
* @return
*/
public static ArrayList<Integer> printMatrix(int [][] matrix) {
if(matrix == null) {
return null;
}
ArrayList<Integer> result = new ArrayList<>();
int row = matrix.length;
int col = matrix[0].length;
int countOfCircle = (Math.min(row, col) + 1) / 2;
for(int i = 0; i < countOfCircle; i++) {
int endX = row - i - 1;
int endY = col - i - 1;
//打印上边
for(int j = i; j <= endY; j++) {
result.add(matrix[i][j]);
}
//打印右边
for(int j = i + 1; j <= endX; j++) {
result.add(matrix[j][endY]);
}
//打印下边
if(endX > i) {
for (int j = endY - 1; j >= i; j--) {
result.add(matrix[endX][j]);
}
}
//打印左边
if(endY > i) {
for (int j = endX - 1; j > i; j--) {
result.add(matrix[j][i]);
}
}
}
return result;
}
思路二
模拟魔方逆时针旋转,我们每次打印矩阵第一行,删除第一行所有元素,然后逆时针旋转矩阵,直到矩阵最后的行为1为止,这时说明已到达最后一个元素。画图解释:假设给定4 X 3矩阵
1. 打印第一行
2. 删除第一行,并逆时针旋转
3. 删除第一行,继续逆时针旋转
4. 删除第一行,继续逆时针旋转
- 删除第一行,继续逆时针旋转
- 删除第一行,已是最后一个元素,结束
/**
* 魔方旋转打印
* @param matrix
* @return
*/
public static ArrayList<Integer> printMatrix2(int [][] matrix) {
if(matrix == null) {
return null;
}
ArrayList<Integer> result = new ArrayList<>();
int row = matrix.length;
while(row != 0) {
for(int i = 0; i < matrix[0].length; i++) {
result.add(matrix[0][i]);
}
//当row == 1时,说明已是最后一个元素
if(row == 1) {
break;
}
matrix = anticlockwiseReverse(matrix);
row = matrix.length;
}
return result;
}
/**
* 逆时针旋转矩阵
* @param matrix
* @return
*/
public static int[][] anticlockwiseReverse(int[][] matrix) {
int row = matrix.length;
int col = matrix[0].length;
//删除已打印的第一行
int[][] newMatrix = new int[col][row - 1];
for(int i = 0; i < col; i++) {
for(int j = 0; j < row - 1; j++) {
newMatrix[i][j] = matrix[j + 1][col - 1 - i];
}
}
return newMatrix;
}
总结
多画图,复杂问题分步解。