[经典算法]优雅实现顺时针打印矩阵

[size=large]记得这是我在Google面试的时候,被问到的一个问题。关于顺时针打印矩阵问题描述,大家可以搜索下题目,大致信息如下:
给定一个m*n的矩阵,要求,从外层顺时针打印一直到打印完所有元素,
如:
1、2*2矩阵
1 2
3 4

输出:1 2 4 3

2、3*4矩阵
1 2 3 4
5 6 7 8
9 1 2 3

输出:1 2 3 4 8 3 2 1 9 5 6 7

乍一看,这道题挺简单,尤其在面试时,以最快速度写出代码为目标,直接用4个for循环手写代码。但在写的过程中,发现要注意的边界问题很多,但最后还是磕磕绊绊写完了。之后没再考虑了,直到最近偶然看到网上的一些解法,遂觉得是否有更优雅的写法。经过思考,其实只需要考虑矩阵的四个坐标,通过四个坐标的边界来控制即可。每次循环完最外层,四个边界缩小一层即可。最后再通过是否有打印输出作为最外层循环结束条件即可。这样一来,只通过一个for循环搞定,从而以最优雅的方法完美解决该问题。同时,最少的循环,避免复杂的边界判断。

废话不多说,直接上代码,欢迎拍砖。[/size]



public class Test {

private boolean valid(int cc, int m, int n){
if( cc >= m && cc <= n ){
return true;
}
return false;
}

public void print(int m, int n, int a[][], boolean visited[][]){
int offsetX[] = new int[]{0,1,0,-1};
int offsetY[] = new int[]{1, 0, -1, 0};

int sX = 0, eX = n - 1;
int sY = 0, eY = m - 1;

boolean flag = false;
do{
if( sX > eX || sY > eY ){
break;
}
int xTmp = sX;
int yTmp = sY;
for( int ii = 0; ii < offsetX.length;){
if( valid( xTmp, sY, eY) && valid(yTmp, sX, eX) && !visited[xTmp][yTmp]){
System.out.print(a[xTmp][yTmp]+"\t");
visited[xTmp][yTmp] = true;
flag = true;
}

if( valid(xTmp + offsetX[ii], sY, eY) && valid(yTmp + offsetY[ii], sX, eX) ){
xTmp += offsetX[ii];
yTmp += offsetY[ii];
}else{
ii++;
}

}
sX++;
eX--;
sY++;
eY--;
}while( flag );
}

public static void main(String[] args) {
int a[][];
int m = (int)(Math.random() * 5)+1;
int n = (int)(Math.random() * 5)+1;

// m = 10;
// n = 1;

a = new int[m][n];
boolean visited[][] = new boolean[m][n];

System.out.println( m + " * " + n);

for( int i = 0; i < m; i++ ){
for( int j = 0; j < n; j++ ){
int tmp = (int)(Math.random() * 10);
a[i][j] = tmp;
visited[i][j] = false;
System.out.print(tmp+"\t");
}
System.out.println();
}
System.out.println();

System.out.println("顺时针打印:");
Test t = new Test();
t.print(m, n, a, visited);
}

}


[size=large]不用考虑打印方向,只通过一个for循环,优雅完成顺时针打印任务。尽可能少的判断边界条件,从而减少错误概率。[/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值