剑指offer-29 顺时针打印矩阵
微信搜索【程序员画工师】关注更多Java编程技术、数据结构与算法、面试题相关内容。
题目
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: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.
思路
把矩阵看成由若干个顺时针方向的圈组成,循环打印矩阵中的每个圈,每次循环打印一个圈。如下图所示
打印一圈通常分为四步,第一步从左到右打印一行;第二步从上到下打印一列;第三步从右到左打印一行;第四步从下到上打印一列。设置四个变量rowStart ,rowEnd,colStart ,colEnd 分别作为行和列的起止坐标,每一步根据起始坐标和终止坐标循环打印。注意:最后一圈有可能不需要四步,有可能只有一行,只有一列,只有一个数字,因此我们要仔细分析打印每一步的前提条件:
•打印第一步,第一步总是需要的。
•打印第二步的前提条件是至少有两列,即rowStart < rowEnd
•打印第三步的前提条件是至少有两行两列,即colStart < colEnd && rowStart < rowEnd)
•打印第四步的前提条件是至少有三行两列,即colStart < colEnd && rowStart+1 < rowEnd
上代码
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
if(matrix.length == 0 || matrix[0].length == 0){
return null;
}
ArrayList<Integer> printList = new ArrayList<Integer>();
int rowStart = 0;
int rowEnd = matrix.length-1;
int colStart = 0;
int colEnd = matrix[0].length-1;
while(rowStart <= rowEnd && colStart <= colEnd){
for(int i = colStart;i <= colEnd;i++){
printList.add(matrix[rowStart][i]);
}
if(rowStart < rowEnd){
for(int i = rowStart+1;i <= rowEnd;i++){
printList.add(matrix[i][colEnd]);
}
}
if(colStart < colEnd && rowStart < rowEnd){
for(int i = colEnd - 1;i >= colStart;i--){
printList.add(matrix[rowEnd][i]);
}
}
if(colStart < colEnd && rowStart+1 < rowEnd){
for(int i = rowEnd - 1;i >= rowStart + 1;i--){
printList.add(matrix[i][colStart]);
}
}
rowStart ++;
rowEnd --;
colStart ++;
colEnd --;
}
return printList;
}
}
剑指中的思路
剑指中的思路也是从外圈到内圈顺序的依次打印,但在判断循环条件结束的时候有所区别。供读者参考:
假设这个矩阵的行数是rows,列数是columns。打印第一圈的左上角的坐标是(0, 0),第二圈的左上角的坐标是(1, 1),依次类推。我们注意到左上角的坐标中行标和列标总是相同的,于是可以在矩阵中选取左上角为(start,start)的一圈作为我们的分析的目标。对于一个55的矩阵,最后一圈只有一个数字,对应的坐标为(2, 2)。5 > 2 * 2;对于一个66的矩阵,最后一圈有4个数字,其左上角的坐标仍是(2, 2)。6 > 2 *2;故循环继续的条件为columns > startX * 2并且rows > startY * 2。
剑指解法Java版
附Java版代码供读者参考
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
if(matrix.length == 0 || matrix[0].length == 0){
return null;
}
ArrayList<Integer> printList = new ArrayList<Integer>();
int rows = matrix.length;
int columns = matrix[0].length;
int start = 0;
while(columns > start * 2 && rows > start * 2){
int endX = columns - 1 - start;
int endY = rows - 1 - start;
for(int i = start;i <= endX;i++){
printList.add(matrix[start][i]);
}
if(start < endY){
for(int i = start + 1;i <= endY;i++){
printList.add(matrix[i][endX]);
}
}
if(start < endY && start < endX){
for(int i = endX - 1;i >= start;i--){
printList.add(matrix[endY][i]);
}
}
if(start < endY - 1 && start < endX){
for(int i = endY - 1;i >= start + 1;i--){
printList.add(matrix[i][start]);
}
}
start ++;
}
return printList;
}
}
旋转魔方的思路
在网上查到还有一种“旋转魔方”的思路,每次遍历完一行就删除该行,然后将剩余矩阵逆时针旋转90度继续遍历第一行,不断循环直到矩阵为空,也很有意思,只是要注意改变了原有数组。附上原文链接,供读者参考:https://www.cnblogs.com/lliuye/p/9107425.html
References
[1] 《剑指offer(第二版)》 何海涛著
程序员画工师公众号,获取更多详细Java、Python、C、前端、小程序、产品相关学习资料,欢迎交流