【面试题】输出数组的问题

题目:输出这样的数组:

01    02    06    07    15    
03    05    08    14    16    
04    09    13    17    22    
10    12    18    21    23    

11    19    20    24    25   

当然你的问题不应该是一位数输出 “1”还是“01”。


这是一类型问题,把数字按照一定的顺序(或者图案、路径)输出,我们姑且称之为“PrintArray”问题吧。

--------------------------------------------------------------------------

遇到这个问题的时候,我们的大部分人会想着怎样在print的时候找到对应的某个位置是那个数,这样的方法也不是说就不行,反正我实在是懒得伤脑筋。那天遇到这个问题的时候,我瞬间想到的是Iterator,熟悉Java集合框架或者STL的朋友肯定对此有所了解:迭代模式。

我们把上面的数看成一个集合,这个集合的元素当然也是需要包装一下的,因为我们在知道元素的值的同时,还想知道它究竟对应于输出时的位置(x,y)。从程序设计的角度讲,元素的迭代方式(即顺序或者路径等等)应该由迭代器决定,元素基本上只是一个pojo,不过我这里只做了简单的实现,并没有把二者分开。

让我们回想一下,STL当中定义的迭代器的类型共有四种,分别是random(随机访问,比如数组,访问时间O(1)),bidirect(双向),forward(单向),input。对于本题来说,bidirect是比较容易实现的,算法也是O(1),而random的话,实际上可以通过执行i次bidirect从形式上实现,但复杂度就成为O(n)了,所以我们只考虑bidirect的情况。

对于bidirect来说,forward和backward实际上经常是逆操作,我下面列出的代码只给出forward,backward的代码看大家自己的兴趣了。

class Iter {
	boolean direction = true;
	int cur = 1;
	int x = 0;
	int y = 0;
	int N;
	int sqrN;

	public Iter(int N) {
		this.N = N;
		this.sqrN = (int) Math.sqrt((double) N);
		if (sqrN * sqrN != N) {
			throw new RuntimeException();
		}
	}

	public boolean forward() {
		if (cur == N) {
			return false;
		}

		if (direction) {
			if (x == sqrN - 1) {
				y += 1;
				direction = false;
			} else if (y == 0) {
				x += 1;
				direction = false;
			} else {
				x += 1;
				y -= 1;
			}

		} else {
			if (y == sqrN - 1) {
				x += 1;
				direction = true;
			} else if (x == 0) {
				y += 1;
				direction = true;
			} else {
				x -= 1;
				y += 1;
			}

		}
		cur++;
		return true;
	}
}
这里的N是输出的最大值,我们要求它是一个完全平方数,当N不符合要求时,抛异常。

代码中的direction可并不是指输出的方向,而是数字在输出时,按照数字顺序输出时呈现在路径上的顺序:从左下角到右上角,或是从右上角到左下角。

这时候有人说我们是要输出这个数组啊,没问题,下面给出main的代码:

public class PrintArray {
	public static void main(String[] args) {
		Iter it = new Iter(25);
		int[][] array = new int[it.sqrN][it.sqrN];
		array[0][0] = it.cur;
		while (it.forward()) {
			array[it.y][it.x] = it.cur;
//			System.out.println(it.cur + "--(" + it.x + "," + it.y + ")");
		}

		for (int i = 0; i < it.sqrN; i++) {
			for (int j = 0; j < it.sqrN; j++) {
				System.out.print(String.format("%02d", array[i][j]) + "\t");
			}
			System.out.println();
		}
	}

}
我们先通过迭代把所有需要输出的数存入一个sqrtN阶的数组中,然后依次打印就行了。你可以把N取得很大,比如我取它为64,那么结果就像这样:

01    02    06    07    15    16    28    29    
03    05    08    14    17    27    30    43    
04    09    13    18    26    31    42    44    
10    12    19    25    32    41    45    54    
11    20    24    33    40    46    53    55    
21    23    34    39    47    52    56    61    
22    35    38    48    51    57    60    62    
36    37    49    50    58    59    63    64   
---------------------------------------------------------------------------------------

这个思路实际上可以用于很多数组输出的问题,比如:

01    28    27    26    25    24    23    22    
02    29    48    47    46    45    44    21    
03    30    49    60    59    58    43    20    
04    31    50    61    64    57    42    19    
05    32    51    62    63    56    41    18    
06    33    52    53    54    55    40    17    
07    34    35    36    37    38    39    16    
08    09    10    11    12    13    14    15   
逆时针旋转的形状输出,那么你只需要修改一下Iter即可。

class Iter2 {
	enum Direction {
		UP, DOWN, LEFT, RIGHT
	}

	Direction direction = Direction.DOWN;

	int cur = 1;
	int x = 0;
	int y = 0;
	int N;
	int sqrN;

	int maxX;
	int maxY;
	int minX;
	int minY;

	public Iter2(int N) {
		this.N = N;
		this.sqrN = (int) Math.sqrt((double) N);
		if (sqrN * sqrN != N) {
			throw new RuntimeException();
		}

		maxX = sqrN - 1;
		maxY = sqrN - 1;
		minX = 0;
		minY = 0;
	}

	public boolean forward() {
		if (cur == N) {
			return false;
		}

		switch (direction) {

		case DOWN:
			if (++y == maxY) {
				direction = Direction.RIGHT;
				++minX;
			} else {

			}
			break;
		case LEFT:
			if (--x == minX) {
				direction = Direction.DOWN;
				++minY;
			}
			break;
		case RIGHT:
			if (++x == maxX) {
				direction = Direction.UP;
				--maxY;
			}
			break;
		case UP:
			if (--y == minY) {
				direction = Direction.LEFT;
				--maxX;
			}
			break;
		default:
			break;

		}
		cur++;
		return true;
	}
}
那么实际上,既然知道了iter可以按照要求输出这些数字,就可以给它配备算法。这种做法有点儿类似STL的算法设计模式。

通过简单的修改forward的代码就可以让数字按照各式各样的图案输出。为了增加趣味,我们让上面的逆时针输出点儿别的:




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值