《剑指Offer》学习笔记--面试题20:顺时针打印矩阵

来源:互联网 发布:淘宝手机详情怎么设置 编辑:程序博客网 时间:2024/05/18 03:53

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

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,8,11,10。

这道题完全没有涉及复杂的数据结构或者高级的算法,看起来是一个很简单的问题。但实际上解决这个问题,会在代码中包含多个循环,并且还需要判断多个边界条件。如果在把问题考虑得很清楚之前就开始写代码,不可避免会越写越混乱。因为解决这个问题的关键在于先要形成清晰的思路,并把复杂的问题分解成若干个简单的问题。

当我们遇到一个复杂问题的时候,可以用图形来帮助我们思考。由于是以从外圈到内圈的顺序依次打印,我们可以把矩阵想象成若干个圈,我们可以用一个循环来打印矩阵,每次打印矩阵中的一个圈。

接下来分析循环结束的条件。假设这个矩阵的行数是rows,列数是columns。打印第一圈的左上角的坐标是(0,0),第二圈的左上角的坐标是(1,1),一次类推。我们注意到,左上角的坐标中行标和列标总是相同的,于是可以再矩阵中选取左上角(start,start)的一圈作为我们分析的目标。

对一个5*5的矩阵而言,最后一圈只有一个数字,对应的坐标为(2,2)。我们发现5>2*2.对于一个6*6的矩阵而言,最后一圈有4个数字,其左上角的坐标仍然为(2,2)。我们发现6>2*2依然成立。于是我们可以得出,让循环继续的条件是columns>startX*2并且rows>startY*2.所以我们可以用如下的循环来打印矩阵:

void PrintMatrixClockwisely(int **numbers, int columns, int rows){if(numbers == NULL || columns <= 0 || rows <= 0)return;int start = 0;while(columns > start * 2 && rows > start * 2){PrintMatrixInCircle(numbers, columns, rows, start);++start;}}

接着我们考虑如何打印一圈的功能,即如何实现PrintMatrixInCircle.我们可以把打印一圈分为四步:

第一步从左到右打印一行

第二步从上到下打印一列

第三步从右到左打印一行

第四步从下到上打印一列

不过值得注意的是,最后一圈有可能退化成只有一行、只有一列,甚至只有一个数字,因此打印这样的一圈就不再需要四步。

因此我们需要仔细分析打印时每一步的前提条件。第一步总是需要的,因为打印一圈至少有一步。如果只有一行,那么就不用第二步了。也就是需要第二步的前提条件是终止行号大于起始行号。需要第三步打印的前提条件是圈内至少有两行两列,也就是说出来要求终止行号大于起始行号之外还要求终止列号大于起始列号,同理,需要打印第四步的前提条件是至少有三行两列,因此要求终止行号比起始行号至少大2,同时终止列号大于起始列号。

通过上述分析我们就可以写出如下的代码:

void PrintMatrixInCircle(int** numbers, int columns, int rows, int start){int endX = columns - 1 - start;int endY = rows -1 - start;//从左到右打印一行for(int i = start; i <= endX; ++i){int number = numbers[start][i];printNumber(number);}//从上到下打印一列if(start < endY){for(int i = start + 1; i <= endY; ++i){int number = numbers[i][endX];printNumber(number);}}//从右到左打印一行if(start < endX && start < endY){for(int i = endX - 1; i >= start; --i){int number = numbers[endY][i];printNumber(number);}}//从下到上打印一列if(start < endX && start < endY - 1){for(int i = endY - 1; i >= start + 1; --i){int number = numbers[i][start];printNumber(number);}}}


0 0