剑指offer(29 顺时针打印矩阵) 题解

剑指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.

思路

把矩阵看成由若干个顺时针方向的圈组成,循环打印矩阵中的每个圈,每次循环打印一个圈。如下图所示
剑指offer(29 顺时针打印矩阵) 题解_第1张图片
打印一圈通常分为四步,第一步从左到右打印一行;第二步从上到下打印一列;第三步从右到左打印一行;第四步从下到上打印一列。设置四个变量rowStart ,rowEnd,colStart ,colEnd 分别作为行和列的起止坐标,每一步根据起始坐标和终止坐标循环打印。注意:最后一圈有可能不需要四步,有可能只有一行,只有一列,只有一个数字,因此我们要仔细分析打印每一步的前提条件:

•打印第一步,第一步总是需要的。
剑指offer(29 顺时针打印矩阵) 题解_第2张图片
•打印第二步的前提条件是至少有两列,即rowStart < rowEnd
剑指offer(29 顺时针打印矩阵) 题解_第3张图片
•打印第三步的前提条件是至少有两行两列,即colStart < colEnd && rowStart < rowEnd)
剑指offer(29 顺时针打印矩阵) 题解_第4张图片
•打印第四步的前提条件是至少有三行两列,即colStart < colEnd && rowStart+1 < rowEnd
剑指offer(29 顺时针打印矩阵) 题解_第5张图片

上代码

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、前端、小程序、产品相关学习资料,欢迎交流
在这里插入图片描述

你可能感兴趣的:(剑指offer)