题目描述
- 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 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.
- 地址: 牛客链接
解题方法
- 采用逐圈打印矩形的方式来打印出整个矩阵
- 那么如何确定一个矩形?
如果是矩形,可以用左上角与右下角唯一确定一个矩形,minR表示矩阵最小行下标,minC表示矩阵最小列下标,maxR代表矩阵最大行下标,maxC表示矩阵最大列下标,(minR,minC),(maxR,maxC)分别代表矩阵左上角和右下角。 - 如何实现逐圈?
每打印完一圈,左上角向右下移动,右下角向左上移动,便确定了内层圈 - 圈会出现三种情况,单行,单列,多行多列,如何打印?
- 若minR = maxR ,说明是单行,那么直接打印单行
- 若minC = maxC,说明是单列,那么直接打印单列
- 否则,便是多行多列的情况,如何能做到不重复打印呢:分为四步去分别打印四条边,假设长为m,宽为n:
- 从左上到右上,打印 m-1 个元素
- 从右上到右下,打印 n-1 个元素
- 从右下到左下,打印 m-1 个元素
- 从左下到左上,打印 n-1个元素
- 上述方法只需遍历一次完整的矩阵元素便可以完成打印。
- 牛客讨论区里还有模拟魔方逆时针旋转方法,先打印第一行元素,然后删除第一行,将删除后的矩阵逆时针旋转,得到新的矩阵。重复上述步骤。
这个方法时间复杂度显然比第一种方法高,不过方法十分巧妙,值得注意。
经验教训
- 左上角与右下角四个值便可以确定一个矩形,如果是正方形,那么只需一个顶点与边长三个值便可以确定
- 如何实现逐圈打印
- 如何做到不重复打印
代码实现
import java.util.ArrayList;
public class Solution {
ArrayList<Integer> res = new ArrayList<>();
public ArrayList<Integer> printMatrix(int [][] matrix) {
if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
return res;
}
int minR = 0;
int minC = 0;
int maxR = matrix.length - 1;
int maxC = matrix[0].length - 1;
while (minR <= maxR && minC <= maxC) {
printEdge(matrix, minR, maxR, minC, maxC);
++minR;
++minC;
--maxR;
--maxC;
}
return res;
}
public void printEdge(int[][] m, int minR, int maxR, int minC, int maxC) {
if (minR == maxR) {
for (int j = minC; j <= maxC; j++) {
res.add(m[minR][j]);
}
}else if (minC == maxC) {
for (int i = minR; i <= maxR; i++ ) {
res.add(m[i][minC]);
}
}else {
for (int j = minC; j < maxC; j++) {
res.add(m[minR][j]);
}
for (int i = minR; i < maxR; i++) {
res.add(m[i][maxC]);
}
for (int j = maxC; j > minC; j--) {
res.add(m[maxR][j]);
}
for (int i = maxR; i > minC; i--) {
res.add(m[i][minC]);
}
}
}
}