剑指Offer_#29_顺时针打印矩阵

剑指Offer_#29_顺时针打印矩阵

Contents

题目

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

限制:

0 <= matrix.length <= 100
0 <= matrix[i].length <= 100

思路分析

按照书中的思路,打印的过程是逐层打印的,从外到内,每一圈都顺时针的打印。
将整个过程分为两层循环,

  • 外层循环:逐渐缩小边界,从最外圈到最内圈。
    • 每一圈遍历的起始点是(start,start),每轮循环,start增加1,即边界向内缩小一圈。
    • 循环条件start * 2 < row && start * 2 <column,可以这样理解:start必然在整个矩阵的左半部分和上半部分,超出整个范围,说明每一圈都遍历完成了,循环可以终止。
  • 内层循环:顺时针打印某一圈的元素。
    • 顺序:模拟顺时针旋转顺序,分别遍历上边界,右边界,下边界,左边界。
      顺序
    • 前提条件:除了上边界之外,其他的边界是否打印是有前提的。
      • 从上到下遍历右边界,条件:至少有两行
      • 从右到左遍历下边界,条件:至少有两行两列
      • 从下到上遍历左边界,条件:至少有三行两列
    • 循环边界条件
      • 每一圈当中的四个角落位置需要注意,不要重复访问。

解答

class Solution {
    int row;
    int column;
    int[] res;
    int x = 0;//res的索引
    public int[] spiralOrder(int[][] matrix) {
        //ERROR:空数组和null不是一个东西
        if(matrix == null || matrix.length == 0) return new int[0];
        //打印每一圈的开始位置(0,0),(1,1)...表示为(start,start)
        int start = 0;
        //ERROR:注意行列的长度不要搞反
        row = matrix.length;
        column = matrix[0].length;
        res = new int[row * column];
        //循环条件:开始点(start,start)应该位于矩阵的左半部分和上半部分
        //即start应小于行数和列数的一半,可以枚举简单的情况,得到这个规律
        //ERROR:不可以写成除法的形式,因为除法会出现向下取整的情况,导致误判
        //while(start < (row / 2) && start < (column / 2)){
        while(row > 2*start && column > 2*start){
            //每次从(start,start)位置开始,顺时针打印一圈
            PrintMatrixInCircle(matrix,start);
            //start++即打印范围向内缩小一圈
            start++;
        }
        return res;
    }

    public void PrintMatrixInCircle(int[][] matrix, int start){
        //右边界
        int endX = column - 1 - start;
        //下边界
        int endY = row - 1 - start;
        //从左到右遍历上边界
        for(int i = start;i <= endX;i++){
            res[x++] = matrix[start][i];
        }
        //从上到下遍历右边界
        //条件:至少有两行
        if(endY > start){
            //边界要排除第一个(因为在上边界里访问过了),即i是从start+1开始而非start
            for(int i = start + 1;i <= endY;i++){
                res[x++] = matrix[i][endX];
            }
        }
        //从右到左遍历下边界
        //条件:至少有两行两列
        if(start < endX && start < endY){
            //同理,要排除第一个
            for(int i = endX - 1;i >= start;i--){
                res[x++] = matrix[endY][i];
            }
        }
        //从下到上遍历左边界
        //条件:至少有三行两列
        if(endY - start > 1 && start < endX){
            //同理,排除第一个
            for(int i = endY - 1;i >= start + 1;--i){
                res[x++] = matrix[i][start];
            }
        }
    }
}
原文地址:https://www.cnblogs.com/Howfars/p/13237140.html