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

来源:互联网 发布:宏源证券交易软件 编辑:程序博客网 时间:2024/06/09 20:46

题目:输出这样的数组:

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
原创粉丝点击