剑指Offer 面试题29. 顺时针打印矩阵(easy)

前往LeetCode做题

题目

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

示例 :

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

思路

数组的顺时针

 ①从左到右
		②
上      从
至      上
下      到
从      下
④
 左至右从 ③

我自己想到的思路是:

  • 建立一个和原数组一样的boolean[][]数组,但访问过的元素置为true。
  • 按照顺时针的顺序,将所有的元素访问完成。如果访问过,就不再访问了。

使用额外空间的解法

使用一个boolean[][] 二维数组,存储已经访问过的位置

这种想法的来源是,之前做过的一题 面试题 13 机器人的运动范围,记录曾经访问过的路径,确保不会再访问。

代码:

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        // 取出异常的输入
        if(matrix.length == 0 || matrix[0].length == 0) return new int[0];
        // 建立一个boolean数组
        boolean[][] visited = new boolean[matrix.length][matrix[0].length];
        int[] ret = new int[matrix.length*matrix[0].length];
        int index = 0;
                    visited[0][0] = true;
                    ret[index++] = matrix[0][0];
        // 从 [0][0]开始遍历
        for (int i=0; i<matrix.length; ){
            for (int j=0; j<matrix[0].length; ){
                
                // 先右
                while(j+1<matrix[0].length && !visited[i][j+1]){
                    // 没有访问过
                    j++;
                    visited[i][j] = true;
                    ret[index++] = matrix[i][j];
                }
                // 否则下
                while(i+1<matrix.length && !visited[i+1][j]){
                    i++;
                    visited[i][j] = true;
                    ret[index++] = matrix[i][j];
                }
                // 否则左
                while(j-1>=0 && !visited[i][j-1]){
                    j--;
                    visited[i][j] = true;
                    ret[index++] = matrix[i][j];
                }
                // 否则上
                while(i-1>=0 && !visited[i-1][j]){
                    i--;
                    visited[i][j] = true;
                    ret[index++] = matrix[i][j];
                }
                // 都不满足,跳出循环
                if(index == ret.length){
                    return ret;
                }
            }
        }
        return ret;
    }
}

更快的解法

  • 找四个标志,分别记录矩阵逻辑上的上下左右四个边界
  • 每次遍历往一行或者一列的时候,更新逻辑上的边界

代码:

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        // 去除异常输入
        if(matrix.length == 0) return new int[0];
        // 建立矩阵的四个边界
        int l = 0;                      // 左边界 left
        int r = matrix[0].length-1;     // 右边界 right
        int t = 0;                      // 上边界 top
        int b = matrix.length-1;        // 下边界 bottom
        // 矩阵的元素个数
        int size = matrix.length*matrix[0].length;
        int[] ret = new int[size];      // 返回值
        int x = 0;                      // 数组下标(重要)

        while(x < size){
            // 保存所有的 left->right
            for(int i=l; i<=r; i++) ret[x++] = matrix[t][i];
            // 最上边一行完毕,上边界下移一位
            if(++t>b) break;
            
            // 保存所有的 top->bottom
            for(int i=t; i<=b; i++) ret[x++] = matrix[i][r];
            // 最右边一列输出完毕,右边界左移一位
            if(--r<l) break;
            
            // 保存所有的 left->right
            for(int i=r; i>=l; i--) ret[x++] = matrix[b][i];
            // 最下边一行输出完毕,下边界上移一位
            if(--b<t) break;
            
            // 保存所有的 bottom->top
            for(int i=b; i>=t; i--) ret[x++] = matrix[i][l];
            // 最左边一列输出完毕,左边界右移一位
            if(++l>r) break;
        }

        return ret;
    }
}

总结:

  • 如果需要定义一个变量作为下标的话,可以尽量使用单词的首字母作为变量名。例如:left - l,right - r
  • 比较重要的语句
    if(++t>b) break;
    
    这一句可以 阻止 去访问,已经访问过了的元素。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值