算法题:剑指 Offer 29. 顺时针打印矩阵(题目+思路+代码+注释)时空 O(N) O(1) 1ms击败97%、52%用户

在这里插入图片描述

题目

剑指 Offer 29. 顺时针打印矩阵

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

示例 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
注意:本题与主站 54 题相同:https://leetcode-cn.com/problems/spiral-matrix/

思路

既然顺时针遍历,那就先自己在纸上画一下,找规律,发现我们可以定义一个转圈的起点 (i,j),然后临时变量left=i,right=j,转圈的时候,不断的增加right,但是不让right到达最右边界,随后让right等于最右边界,继续让left自增,但是不到边界,然后再right递减,也不到边界,再让left递减,不到边界,就完成了一个圈。转圈的时候还需要几个辅助变量,例如mini maxi minj maxj用来标记这个圈的四个角,限制住免得在里面转圈的时候走出去了,另外也可以每次往里面走的时候让边界自增、自减即可。
我画个图吧,更好理解,按照箭头的方式遍历,每次向一个方向遍历的时候不要碰到最边上的点。
在这里插入图片描述
上面是个正方形的,能够直接打圈打完,但是如果是个长方形呢,也属于矩形,如果是长大于宽的长方形那么中间就会留下一行,直接最后出了循环遍历掉即可
在这里插入图片描述
还有可能长小于宽,那就是留下来 一竖,也直接遍历掉即可
在这里插入图片描述

代码

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if (matrix.length > 0 && matrix[0].length > 0) {
            int i = 0, j = 0, count = 0, m = matrix.length, n = matrix[0].length, mini = 0, maxi = m - 1, minj = 0, maxj = n - 1;
            int[] ret = new int[m * n];
            while (mini < maxi && minj < maxj){
                //从(i,j)开始
                int left = i,right = j;
                //从左上角往右上角但是不包括右上角
                while (right < maxj){
                    ret[count++] = matrix[left][right++];
                }
                right = maxj;
                //从右上角往右下角但是不包括右下角
                while (left < maxi){
                    ret[count++] = matrix[left++][right];
                }
                left = maxi;
                //从右下角往左下角但是不包括左下角
                while (right > minj){
                    ret[count++] = matrix[left][right--];
                }
                right = minj;
                //从左下角到左上角但是不包括左上角
                while (left > mini){
                    ret[count++] = matrix[left--][right];
                }
                //修改参数,继续向内循环
                mini++;
                maxi--;
                minj++;
                maxj--;
                i++;
                j++;
            }
            //如果有个最中心的一个点或者一行,因为没办法形成一个圈了
            if (count < ret.length  && ret[count] == 0){
                int left = i,right = j;
                while (right <= maxj){
                    ret[count++] = matrix[left][right++];
                }
            }
            //如果中间有一竖也没办法形成一个圈了,记得(i,j)被上面刚已经用过了,不再用
            if (count < ret.length  && ret[count] == 0){
                int left = i+1,right = j;
                while (left <= maxi){
                    ret[count++] = matrix[left++][right];
                }
            }
            return ret;
        }
        return new int[0];
    }
}
posted @ 2021-09-02 17:11  HumorChen99  阅读(2)  评论(0编辑  收藏  举报  来源