您的位置:首页 > 职场人生

程序员面试题精选100题(51)-顺时针打印矩阵

2012-12-01 16:30 417 查看
程序员面试题精选100题(51)-顺时针打印矩阵

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

例如:如果输入如下矩阵:

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。

               通常当我们遇到一个复杂的问题的时候,我们可以用图形帮助我们思考。由于我们是以从外圈到内圈的顺序依次打印,我们在矩阵中标注一圈作为我们分析的目标。在下图中,我们设矩阵的宽度为columns,而其高度为rows。我们我们选取左上角坐标为(startX,
startY),右下角坐标为(endX, endY)的一个圈来分析。
 
 
 
 
 
 
 
startX, startY
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
endX, endY
 
 
 
 
 
 
 
由于endX和endY可以根据startX、startY以及columns、rows来求得,因此此时我们只需要引入startX和startY两个变量。我们可以想象有一个循环,在每一次循环里我们从(startX,
startY)出发按照顺时针打印数字。

接着我们分析这个循环结束的条件。对一个5×5的矩阵而言,最后一圈只有一个数字,对应的坐标为(2,
2)。我们发现5 > 2 * 2。对一个6×6的矩阵而言,最后一圈有四个数字,对应的坐标仍然为(2,
2)。我们发现6 > 2 * 2依然成立。于是我们可以得出,让循环继续的条件是columns
> startX * 2 && rows > startY * 2。

接下来我们分析如何在PrintMatrixInCircle中按照顺时针的顺序打印一圈的数字。如同在图中标注的那样,我们可以分四步来打印:第一步是从左到右打印一行(上图中黄色区域),第二步是从上到下打印一列(上图中绿色区域),第三步从右到左打印一行(上图中蓝色区域),最后一步是从下到上打印一列(上图中紫色区域)。也就是我们把打印一圈数字这个问题,分解成四个子问题。我们可以为每个子问题定义一个函数。四个步骤对应的函数名称我们分别定义为:PrintARowIncreasingly,PrintAColumnIncreasingly,PrintARowDecreasingly和PrintAColumnDecreasingly。

现在我们暂时不考虑如何去实现这四个函数,而是先考虑我们需要分别给这些函数传入哪些参数。第一步打印一行时,所有的数字的行号是固定的(startY),不同数字的列号不同。我们需要传入一个起始列号(startX)和终止列号(endX)。第二步打印一列时,所有的数字的列号是固定的,不同的数字的行号不同。我们需要传入一个起始行号(startY
+ 1)和一个终止行号(endY)。第三步和第四步和前面两步类似,读者可以自己分析。

接下来我们需要考虑特殊情况。并不是所有数字圈都需要四步来打印。比如当一圈退化成一行的时候,也就是startY等于endY的时候,我们只需要第一步就把所有的数字都打印完了,其余的步骤都是多余的。因此我们需要考虑第二、三、四步打印的条件。根据前面我们分析,不难发现打印第二步的条件是startY
< endY。对于第三步而言,如果startX等于endX,也就是这一圈中只有一列数字,那么所有的数字都在第二步打印完了;如果startY等于endY,也就是这一圈中只有一行数字,那么所有的数字都在第一步打印完了。因此需要打印第三步的条件是startX
< endX && startX < endY。第四步最复杂,首先startX要小于endX,不然所有的数字都在一列,在第二步中就都打印完了。另外,这个圈中至少要有三行数字。如果只有一行数字,所有数字在第一步中打印完了;如果只有两行数字,所有数字在第一步和第三步也都打印完了。因此打印第四步需要的条件是startY
< endY – 1。

测试程序如下:
#include<iostream>

using namespace std;

const int N=5;

void printNumber(int number);

void PrintMatrixInCircle(int** numbers,int columns,int rows,int start);

//如下循环打印矩阵

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;

   }

}

//每次打印一圈,并每次判断条件

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][endY];
 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);
}

  }

}

void printNumber(int number)

{

   cout<<number<<endl;

}

int main()

{

  int a

={{1,2,3,4,5},{2,3,4,5,6},{1,3,4,6,5},{2,3,4,7,6},{1,8,2,5,4}};

  PrintMatrixClockwisely((int**)a,N,N);

  return 0;

}


参考来源:《剑指offer名企面试官精讲典型编程题》——何海涛
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: