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

《剑指offer》面试题20 顺时针打印矩阵

2014-06-21 20:52 405 查看
题目描述:

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

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.

很容易想到的是 我们采用递归来处理这个问题。 但问题是我们如何判断打印的方向?不妨设置一个变量direct 表示我们打印的方向,比如direct=1 继续打印右边的矩阵元素,direct=2打印下面的元素。那如何判断走到边界处需要改变方向呢?很容易,我们对于访问过得元素置为0就可以了,这样就可以避免重复访问了。

#include <iostream>
#include "string.h"
using namespace std;

int a[1010][1010];
int m,n;
static int cnt;

void print(int i,int j,int c[][1010],int dir)
{
cout<<c[i][j]<<' ';
c[i][j]=0; //once we print c[i][j],let it equals zero,so that it can not be printed again

cnt++;
if(cnt==n*m)
return ; //it showed we have printde the whole array,so it is the end of recurism

if(dir==1)
{
if (c[i][j+1]) //go on to print a[i][j+1]
{
print(i, j+1, c, dir);
}
else
{
print(i+1,j,c,dir+1); //end of line,so that have to change direct
}
}
else if(dir==2)
{
if(c[i+1][j])
{
print(i+1, j, c, dir);
}
else
{
print(i,j-1,c,dir+1);
}
}
else if(dir==3)
{
if(c[i][j-1])
{
print(i, j-1, c, dir);
}
else
{
print(i-1, j, c, dir+1);
}
}
else if(dir==4)
{
if(c[i-1][j])
{
print(i-1, j, c, dir);
}
else
{
print(i, j+1, c,1);
}
}
return ;
}
int main(int argc, const char * argv[])
{
while(cin>>m>>n)
{
memset(a, 0, sizeof(a));
cnt=0;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
int direct=1;
if(n==1)
direct=2;
print(1, 1, a, direct);
cout<<endl;
}
return 0;
}

输入为
4 4
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


但是这样的递归程序有个问题,就是当二维数组的规模不是很大的时候是完全可以运行的,但规模增长的时候很有可能会栈溢出,而且时间效率也不高,我们需要另寻一种高效的方法来解决,最好是递推来解决。

我们可以想到每次打印的时候是一圈一圈的进行打印的,如下图所示:



图片来源于  http://zhedahht.blog.163.com/blog/static/254111742010111112236313/ 

我们假设 每一圈打印的起始点(左上角)坐标分别为startX,startY,右下角坐标为endX,endY,这两个点定义了我们打印的范围。我们需要做的就是依次打印出每个圈。

观察即可发现,起始点坐标依次是(0,0),(1,1)。。。判断边界条件是 startX *2<row && startY *2<column,其实startX=startY。

剩下的问题就是如何打印出每一圈。

首先 依次向右打印元素是必须的。

那什么样的情况下需要向下打印呢?由图可以看出 应该是 endX>startX 。

需要向左打印的条件是什么呢?也很明显,应该是endY>startX。 

那就剩下需要考虑向上打印完成完整的一圈打印了。思考一下便可得到  endX>startX+1 。

至此完整的程序也就出来了。

最后再看一下输入输出的格式。

题目描述:
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵:
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.

输入:
输入可能包含多个测试样例,对于每个测试案例,

输入的第一行包括两个整数m和n(1<=m,n<=1000):表示矩阵的维数为m行n列。

接下来的m行,每行包括n个整数,表示矩阵的元素,其中每个元素a的取值范围为(1<=a<=10000)。

输出:
对应每个测试案例,输出一行,

按照从外向里以顺时针的顺序依次打印出每一个数字,每个数字后面都有一个空格。

样例输入:
4 41 2 3 45 6 7 89 10 11 1213 14 15 16

样例输出:
1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10


程序如下:

#include <iostream>
#include "stdio.h"
using namespace std;

int a[1010][1010];
int m,n;

void print(int c[][1010],int row,int column,int start)
{
int end_x=row-1-start;
int end_y=column-1-start;

for(int i=start;i<=end_y;i++)
cout<<c[start][i]<<' ';

if(end_x>start)
{
for(int j=start+1;j<=end_x;j++)
cout<<c[j][end_y]<<' ';
}

if(start<end_x &&start<end_y)
{
for(int i=end_y-1;i>=start;i--)
cout<<c[end_x][i]<<' ';
}
if(start<end_y&&start<end_x-1)
{
for(int j=end_x-1;j>start;j--)
cout<<c[j][start]<<' ';
}
}
int main()
{
while (cin>>m>>n)
{
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
cin>>a[i][j];

for(int i=0;2*i<m && 2*i<n;i++)
print(a,m,n,i);
cout<<endl;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  剑指offer