顺时针打印矩阵java

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyang0304/article/details/82314837

剑指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

通过画图可以知道,其实就是若干个圈,依次打印出每个圈。而每个圈都要按照顺时针的顺序打印,即4个循环,先从左到右,再从上到下,再从右到左,再从下到上,只是最后一圈,可能只剩下其中的1步或3步。那么问题的关键就是找出一个矩阵可以转换成多少圈。注意要考虑行列不等的矩阵,要从最小的行数或列数下手,推算一个矩阵的圈数。这需要比较好的数学功底,先看4*4以及6*6这种情况,行列数相等,圈数为行数/2或列数/2,因此,可以初步猜测圈数是行列数最小的那个除以2,再考虑特殊情况,假如只有1行3列,那么圈数为1,此时1<3,圈数如果按1/2的方式算,为0,不对,需要+1,即min{行数,列数}/2+1,再带到4*4的情况,又多了一圈,因此需要改变min中情形,由程序中/的特性,将min{行数,列数}-1后/2,带入上述2种情形,均满足,再检验一下2*3,2*4,3*4等情形均符合,因此,最终圈数公式为[min{行数,列数}-1]/2。推算出这个公式后,剩下工作就是按照每圈进行4个方向的遍历即可。代码如下:

public ArrayList<Integer> printMatrix(int[][] array) {
        ArrayList<Integer> result = new ArrayList<>();
        if (array.length == 0) {
            return result;
        }
        int n = array.length;     //行数
        int m = array[0].length;  //列数
        if (m == 0) {
            return result;
        }
        int layers = (Math.min(n, m) - 1) / 2 + 1;  //求圈数
        for (int i = 0; i < layers; i++) {
            //打印每周
            for (int k = i; k < m - i; k++) {
                result.add(array[i][k]);  //从左到右
            }
            for (int j = i + 1; j < n - i; j++) {
                result.add(array[j][m - i - 1]);   //从右上到右下
            }
            for (int k = m - i - 2; (k >= i) && (n - i - 1 != i); k--) {
                result.add(array[n - i - 1][k]);   //从右到左
            }
            for (int j = n - i - 2; (j > i) && (m - i - 1 != j); j--) {
                result.add(array[j][i]);  //从左下到左上
            }
        }
        return result;
    }

剑指offer中提供的思路其实要更容易一些,首先分析循环结束的条件,打印第一圈左上角坐标为(0,0),第二圈左上角坐标为(1,1),以此类推每次循环的行列起始坐标都是相同的(start,start)。因此可以分析出循环继续的条件是columns > startX*2并且rows > startY*2。有了循环继续的条件后,我们要分析每次循环那4步的前提条件。第一步肯定是必定会经过的,因为打印一圈至少有一步。第二步的前提是终止行号大于起始行号,第三步的前提是终止行号大于起始行号,终止列号大于起始列号,因为圈内至少有2行2列,第四步的前提条件是终止行号比起始行号至少大2,终止列号大于起始行号,即至少有3行2列。代码如下:

    public ArrayList<Integer> printMatrix(int[][] matrix) {
        ArrayList<Integer> list = new ArrayList<>();
        if (matrix == null)
            return list;
        int start = 0;
        while (matrix[0].length > start * 2 && matrix.length > start * 2) {
            printOneCircle(matrix, start, list);
            start++;
        }
        return list;
    }

  private void printMatrixInCircle(int[][] matrix, int start, ArrayList<Integer> list) {
        int endX = matrix[0].length - 1 - start;  //列
        int endY = matrix.length - 1 - start;  //行
        //从左往右
        for (int i = start; i <= endX; i++) {
            list.add(matrix[start][i]);
        }
        //从上往下
        if (start < endY) {
            for (int i = start + 1; i <= endY; i++) {
                list.add(matrix[i][endY]);
            }
        }
        // 从右往左(判断是否会重复打印)
        if (start < endX && start < endY) {
            for (int i = endX - 1; i >= start; i--)
                list.add(matrix[endY][i]);
        }
        // 从下往上(判断是否会重复打印)
        if (start < endX && start < endY - 1) {
            for (int i = endY - 1; i >= start + 1; i--)
                list.add(matrix[i][start]);
        }

    }

猜你喜欢

转载自blog.csdn.net/huyang0304/article/details/82314837