剑指offer-顺时针打印矩阵

题目描述

  • 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 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.
  • 地址: 牛客链接

解题方法

  • 采用逐圈打印矩形的方式来打印出整个矩阵
  • 那么如何确定一个矩形
    如果是矩形,可以用左上角与右下角唯一确定一个矩形,minR表示矩阵最小行下标,minC表示矩阵最小列下标,maxR代表矩阵最大行下标,maxC表示矩阵最大列下标,(minR,minC),(maxR,maxC)分别代表矩阵左上角和右下角。
  • 如何实现逐圈
    每打印完一圈,左上角向右下移动,右下角向左上移动,便确定了内层圈
  • 圈会出现三种情况,单行,单列,多行多列,如何打印?
    • 若minR = maxR ,说明是单行,那么直接打印单行
    • 若minC = maxC,说明是单列,那么直接打印单列
    • 否则,便是多行多列的情况,如何能做到不重复打印呢:分为四步去分别打印四条边,假设长为m,宽为n:
      • 从左上到右上,打印 m-1 个元素
      • 从右上到右下,打印 n-1 个元素
      • 从右下到左下,打印 m-1 个元素
      • 从左下到左上,打印 n-1个元素
  • 上述方法只需遍历一次完整的矩阵元素便可以完成打印。
  • 牛客讨论区里还有模拟魔方逆时针旋转方法,先打印第一行元素,然后删除第一行,将删除后的矩阵逆时针旋转,得到新的矩阵。重复上述步骤。
    这个方法时间复杂度显然比第一种方法高,不过方法十分巧妙,值得注意。

经验教训

  • 左上角与右下角四个值便可以确定一个矩形,如果是正方形,那么只需一个顶点与边长三个值便可以确定
  • 如何实现逐圈打印
  • 如何做到不重复打印

代码实现

import java.util.ArrayList;
public class Solution {
    ArrayList<Integer> res = new ArrayList<>();
    public ArrayList<Integer> printMatrix(int [][] matrix) {
        if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
           return res;
        }
        //用二维数组存储矩阵
        //minR表示矩阵最小行下标,minC表示矩阵最小列下标
        //maxR代表矩阵最大行下标,maxC表示矩阵最大列下标
        //(minR,minC),(maxR,maxC)分别代表矩阵左上角和右下角,和矩形类似,用来确定某一层
        int minR = 0;
        int minC = 0;
        int maxR = matrix.length - 1;
        int maxC = matrix[0].length - 1;
        //按圈打印矩阵,直至右下角元素超过左上角元素
        while (minR <= maxR && minC <= maxC) {
            printEdge(matrix, minR, maxR, minC, maxC);
            //左上角向右下移动,右下角往左上移动
            ++minR;
            ++minC;
            --maxR;
            --maxC;
        }
        return res;
    }

    //根据给定的左上角与右下角,打印该矩形(圈)的元素
    public void printEdge(int[][] m, int minR, int maxR, int minC, int maxC) {
       if (minR == maxR) { //当前圈只有一行
           for (int j = minC; j <= maxC; j++) {
               res.add(m[minR][j]);
           }
       }else if (minC == maxC) { //当前圈只有一列
           for (int i = minR; i <= maxR; i++ ) {
               res.add(m[i][minC]);
           }
       }else { //当前圈多行多列,三个三个打印
           //从左上向右上
           for (int j = minC; j < maxC; j++) {
               res.add(m[minR][j]);
           }
           //从右上向右下
           for (int i = minR; i < maxR; i++) {
               res.add(m[i][maxC]);
           }
           //从右下到左下
           for (int j = maxC; j > minC; j--) {
               res.add(m[maxR][j]);
           }
           //从左下到左上
           for (int i = maxR; i > minC; i--) {
               res.add(m[i][minC]);
           }
       }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值