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

这篇博客介绍了两种方法实现矩阵的螺旋顺序遍历。方法一是通过模拟路径,从左上角开始,根据四个方向进行遍历,遇到边界或已访问位置则改变方向;方法二是按层遍历,从外向内逐层添加元素。两种方法的时间复杂度和空间复杂度均为O(mn),其中m和n分别为矩阵的行数和列数。
摘要由CSDN通过智能技术生成

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

示例 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]

方法一:模拟


可以模拟打印矩阵的路径。初始位置是矩阵的左上角,初始方向是向右,当路径超出界限或者进入之前访问过的位置时,顺时针旋转,进入下一个方向。

判断路径是否进入之前访问过的位置需要使用一个与输入矩阵大小相同的辅助矩阵 visited,其中的每个元素表示该位置是否被访问过。当一个元素被访问时,将 visited 中的对应位置的元素设为已访问。

如何判断路径是否结束?由于矩阵中的每个元素都被访问一次,因此路径的长度即为矩阵中的元素数量,当路径的长度达到矩阵中的元素数量时即为完整路径,将该路径返回。

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if(matrix.length == 0){
            return new int[0];
        }
        int row = matrix.length;//行的边界
        int col = matrix[0].length;//列的边界
        boolean[][] isVisited = new boolean[row][col];//判断是否遍历
        int n = row*col;//数字的个数
        int[] nums = new int[n];
        int[][] directions = new int[][]{{0,1},{1,0},{0,-1},{-1,0}};
        int x = 0;
        int y = 0;//初始索引位置
        int directionsIndex = 0;//初始方向索引
        for(int i = 0;i < n;i++){
            nums[i] = matrix[x][y];
            isVisited[x][y] = true;//设置成已经访问
            int nextX = x+directions[directionsIndex][0],nextY=y+directions[directionsIndex][1];//按照此方向的下一个索引
            if(nextX < 0 || nextX >= row || nextY < 0 || nextY >= col || isVisited[nextX][nextY]){
                //若下一节点的索引值越界或者已经访问,则调整方向
                directionsIndex = (directionsIndex + 1 ) % 4;
            }
            x = x + directions[directionsIndex][0];
            y = y + directions[directionsIndex][1];//下一个未访问的节点
        }
        return nums;
    }
}
//时间复杂度:O(mn)
//空间复杂度:O(mn) 用于存储是否访问矩阵isVisited[][]

方法二:按层模拟

可以将矩阵看成若干层,首先打印最外层的元素,其次打印次外层的元素,直到打印最内层的元素。

定义矩阵的第 k 层是到最近边界距离为 k 的所有顶点。例如,下图矩阵最外层元素都是第 1层,次外层元素都是第 2 层,剩下的元素都是第 3 层。

[[1, 1, 1, 1, 1, 1, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 2, 3, 3, 3, 2, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 1, 1, 1, 1, 1, 1]]

class Solution {
    //按层模拟
    public int[] spiralOrder(int[][] matrix) {
        if(matrix.length == 0){
            return new int[0];
        }
        int top = 0;
        int bottom = matrix.length - 1;
        int left = 0;
        int right = matrix[0].length - 1;//第一层的上下左右边界
        int[] nums = new int[matrix.length * matrix[0].length];//创建返回数组
        int count = 0;//统计次数
        while(left <= right && top <= bottom){//直到4个边界重合
            for(int col = left;col <= right;col++){//添加最上层
                nums[count++] = matrix[top][col];
            }
            for(int row = top+1;row <= bottom;row++){//添加最右侧
                nums[count++] = matrix[row][right];
            }
            if(left < right && top < bottom){//这个条件必须加,因为可能不需要添加下层和左侧,如上述的第3层 就没有最下层,和最左侧
                for(int col = right - 1;col >=left;col--){//添加最下层
                    nums[count++] = matrix[bottom][col];
                }
                 for(int row = bottom -1;row >= top+1;row--){//添加最左侧
                     nums[count++] = matrix[row][left];
                }
            }
            top++;
            left++;
            right--;
            bottom--;
        }
        return nums;
    }
}
//时间复杂度:O(mn)
//空间复杂度:O(1)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值