跳至主要內容

29-顺时针打印矩阵

daipeng大约 3 分钟

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

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

输入: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]

第一种 一般方法

这道题主要是对于边界情况判断比较多,同时需要考虑一行、一列的情况。

对于一行 一列这两种情况,我提前做了判断,while循环里不必去兼容这种情况。

public ArrayList<Integer> printMatrix(int [][] matrix) {
        ArrayList<Integer> list = new ArrayList<>();
        if (matrix == null || matrix.length < 1) {
            return list;
        }
        int rows = matrix.length;
        int cols = matrix[0].length;
        //一行
        if (rows == 1) {
            for (int i = 0; i < cols; i++) {
                list.add(matrix[0][i]);
            }
            return list;
        }
    //一列
        if (cols == 1) {
            for (int i = 0; i < rows; i++) {
                list.add(matrix[i][0]);
            }
            return list;
        }
        int start = 0;
        while (start * 2 < rows && start * 2 < cols) {
// 从左到右 肯定存在
            for(int i = start; i <= cols - start - 1; i++) {
                list.add(matrix[start][i]);
            }
            int curCol = cols - start - 1;
//从右上到右下  当前的col必须大于start值
            if(curCol > start){
                for(int i = start+1; i <= rows - start - 1; i++) {
                    list.add(matrix[i][curCol]);
                }
            }
            int curRow  = rows - start - 1;
// 从右下到左下 当前的row必须大于开始行号
            if(curRow > start){
                for(int i = cols - start - 2; i >= start; i--) {
                    list.add(matrix[rows - start - 1][i]);
                }
            }
  //从左下到左上 当前列不能是start列
            if(start != curCol) {
                for (int i = rows - start - 2; i >= start + 1; i--) {
                    list.add(matrix[i][start]);
                }
            }
            start++;
        }
        return list;
    }

可以看到,这种方法写的比较复杂。

第二种 计算层数

我们可以先计算出需要循环多少圈,然后根据圈数,来计算左->右 上->下 右->左 下->上的起止位置。

 public int[] spiralOrder(int[][] matrix) {
        if (matrix == null) {
            return null;
        }
        if (matrix.length == 0) {
            return new int[0];
        }
        int rows = matrix.length;
        int cols = matrix[0].length;
        List<Integer> data = new ArrayList<>();
        int layerCount = (Math.min(rows, cols) + 1) / 2; //需要打印的圈数 
        for (int k = 0; k < layerCount; k++) {
            for (int i = k, j = k; j < cols - k; j++) {
                data.add(matrix[i][j]);
            }
            for (int j = cols - k - 1, i = k + 1; i < rows - k; i++) {
                data.add(matrix[i][j]);
            }
            for (int j = cols - k - 2, i = rows - k - 1; j >= k && i > k; j--) {
                data.add(matrix[i][j]);
            }
            for (int j = k, i = rows - k - 2; i > k && j != cols - k - 1; i--) {
                data.add(matrix[i][j]);
            }
        }
        return data.stream().mapToInt(Integer::valueOf).toArray();
}

这种在计算起止点时需要考虑的东西多一些,尤其是最后两个for循环,终止条件要考虑仔细,无遗漏才可以。

第三种 更清晰的方法

还是按照圈数来遍历,但是使用4个变量,分别表示 最低的row 最高的row 最左的col 最右的col,在遍历完一圈后,将这个四个变量进行相应的增减,打印时的起止点依据这4个变量计算即可。

public int[] spiralOrder2(int[][] matrix) {
        if (matrix == null) {
            return null;
        }
        if (matrix.length == 0) {
            return new int[0];
        }
        int rows = matrix.length;
        int cols = matrix[0].length;
        int[] result = new int[rows * cols];
        int l = 0,//最左的col
          r = cols - 1, //最右的col
          t = 0,//最低的row
           b = rows - 1,//最高的row
           x = 0;
        while(true){
            for(int j = l; j <= r; j++){
                result[x++] = matrix[t][j];
            }
            if(++t > b){ //最低的row要小于最高的row,否则会重合
                break;
            }
            for (int i = t; i <= b; i++) {
                result[x++] = matrix[i][r];
            }
            if(--r < l){ //最右的col要大于最左的col
                break;
            }
            for(int j = r; j >= l;j--){
                result[x++] = matrix[b][j];
            }
            if(--b < t){
                break;
            }
            for (int i = b; i >= t; i--) {
                result[x++] = matrix[i][l];
            }
            if(++l > r){
                break;
            }
        }
        return result;
    }