面试题20:顺时针打印矩阵

题目

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

面试题20:顺时针打印矩阵_第1张图片
image.png

则依次打印出:1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10

这题考察分析归纳能力,至少要发现如下规律:

  1. 打印是以圈为单位,每圈最多包含4个边。
  2. 每个圈的起点的坐标是[0,0],[1,1],[2,2],以此类推,横纵坐标相等,且以步长为1递增。
  3. 根据2可以得到一个结论:最后一圈的起点坐标的两倍必定大于矩阵的横坐标或者纵坐标。比如一个3列,8行的矩阵。其循环次数(圈的个数)受制于3而不是8(列和行中小的一个)。循环的次数应该2次,当然第二次循环可能没有完整的四个边。如果是4列,也依然只能循环两次。简单的用数学描述:start*2,其中start从0开始(数组从零开始)。
  4. 那么接下来要研究的就是什么情况下打印4边,什么情况下3边等等(残缺的圈都是最后一圈)。首先我们规定每一边都尽可能到达边界,比如上图例子中第一圈,第一边应该打印出4,而不是把4留给第二边。这样我们发现,打印最后一圈的时候第一边总会打印不需要条件,第二圈打印的条件是第一边打印出了(这个条件永远成立)并且终止列必须大于起始列,第三圈打印的条件是第二边打印出了并且终止行必须大于起始行,第四圈打印的条件是第三边必须打印出了并且终止行大于起始行+1。

发现了这些规律,写代码就非常轻松简单了。如果没发现这些规律,那么代码根本就不用写了。

分析归纳,并抽象出问题中所含的逻辑。比较好的办法是举几个具体的列子,具体例子才能让你具体的分析,然后多举几个特殊点的例子,综合这些例子看看有哪些共同点。

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

private void printCircle(int[][] matrix, int start, ArrayList arrayList) {
    int columnEnd = matrix[0].length - 1 - start;
    int rowEnd = matrix.length - 1 - start;
    for (int i = start; i <= columnEnd; i++) {
        arrayList.add(matrix[start][i]);
    }
    if (start < rowEnd) {
        for (int i = start + 1; i <= rowEnd; i++) {
            arrayList.add(matrix[i][columnEnd]);
        }
    }
    if (start < rowEnd && start < columnEnd) {
        for (int i = columnEnd - 1; i >= start; i--) {
            arrayList.add(matrix[rowEnd][i]);
        }
    }
    if (start + 1 < rowEnd && start < columnEnd) {
        for (int i = rowEnd - 1; i > start; i--) {
            arrayList.add(matrix[i][start]);
        }
    }
}

你可能感兴趣的:(面试题20:顺时针打印矩阵)