最近在
javaeye
上看到一道面试题。
要求打印出:
int
i = 5;
1
2 3 4 5
16
17 18 19 6
15
24 25 20 7
14
23 22 21 8
13
12 11 10 9
int
i = 6;
1
2 3 4 5 6
20
21 22 23 24 7
19
32 33 34 25 8
18
31 36 35 26 9
17
30 29 28 27 10
16
15 14 13 12 11
从发贴人的意图来看,这应该是一道
java
面试题(
http://www.iteye.com/topic/545378?page=1
);
看到很多热心的网友给出各种各样的答案,其中有
java
、
c
、
ruby
的。看到很多人这么有兴趣,我也给出了自己的答案。
不过我还想到另外两个问题:
1
、什么语言的题目?
2
、考官的目的?
如果是
c
语言,那么第二个问题一定是考查面试者的算法。如果这是一道
java
面试题,那就很难说了。第一,跟考官的水平和思维很大的关系;
第二,确实考查面试者的算法能力;
第三,考查的是面向对象分析和设计的能力。
本人更倾向于第三种,为什么呢?因为主要是
java
本身是面向对象的语言;其次算法已经很成熟了,平时工作可参考资料就可以实现。
很多网友给出的答案大多都是基于面向过程的算法实现。如果这些实现放在其他面向过程的语言中可能非常适合,如果在
java
中就不合适了。
java
是一个面向对象的语言,面向对象的出现无非是为了解决面向过程中出现的一些缺点:可维护性、可扩展性、代码可复用性差等。所以在
java
语言中应该是考查我们的面向对象分析和设计的能力,而不是算法实现
!
如果我是考官,那么让我看一个人的算法实现是很痛苦的事情。首先我没有那么多脑力计算出这个算法实现是否正确,其次让我把代码一行一行敲入计算机,那肯定没有这个功夫。
所以,大家以后碰到这类题目不要一上来就冥思苦想,然后写出让人难于看懂的算法实现。当然也有例外,那就是有些考官本身水平和思维有限,就是想看到你是否有代码。
3
年前我在面试中也碰到类似的题目,我的做法仅仅是说明为了实现这个功能我有那些类和关键方法。结果很不利,所以这个跟考官的水平和思维有很大的关系。
像这道面试题,我第一次看到就联想到这个是一个贪吃蛇游戏的简化版。如果联想不到呢,那就没辙啦。那也不会。
首先,我们从上面可以看出这是一个矩阵,它的高度和宽度是一样的,矩阵中有一些格子存放数字,这个格子就是一个点。
其次,这些数字的增长是有规律的,即顺时针而且不断内旋。
所以我们可以得到两个关键的类:点(
Point
)和方向(
Direction
)。既然存在方向这个概念,那么一定存在它的主体,比如车、火箭等,这里我们就用蛇(
Snake
)吧。
既然有了类,那么他们有那些属性呢?
想到点我们必定也能想到坐标中用
x
、
y
变量来表示。另外跟我们问题域有关的是在这个点上要记录一些信息。所以点有以下定义:
class
Point {
private
int
x
;
private
int
y
;
private
String
val
;
}
方向这个概念比较抽象,在我们要研究的问题域中方向有向左、向右、向下、向上,而且有一定的范围。所以在给定范围的方向上,类
Direction
应该知道一个点是否出界,能够计算本方向上下一个点是什么。另外从题目上看,方向的变化规律是顺时针的,所以类
Direction
应该也能够知道它下一个方向是什么。所以方向有以下定义:
abstract
class
Direction {
int
size
;
abstract
public
Point nextPoint(Point p);
//
下个点
abstract
public
Direction next(Point p);
//
下一个方向
abstract
public
boolean
isOut(Point point);
//
是否在本方向上出界
}
类
Direction
有四个子类,分别是右、左、下、上。这四个子类通过
next
方法返回另一个
Direction
构成类一个顺时针。
再来看看另外一个核心类
Snake
,它有那些属性呢?这个
Snake
会在一个方向和指定范围内进行游走,碰到壁什么的会掉头,不走已经走过的点。所以它能记住自己走过的点,并且在那里做些标记。最后还会打印出自己走过的路径。
public
class
Snake {
int
size
;
Direction
direct
;
Point
next
;
Map<String,
Point>
map
=
new
HashMap<String, Point>();
//
记录走过的点
public
Snake(
int
size, Direction direct, Point point) {
this
.
size
= size;
this
.
direct
= direct;
next
= point;
map
.put(key(
next
),
next
);
}
//
游走
public
void
run() {
for
(
int
i = 2; i <
size
*
size
+ 1;
i++) {
Point tempNext =
direct
.nextPoint(
next
);
//
如果在一个方向上出界或者已经走过的点要掉头
if
(
direct
.isOut(tempNext)
|| containsPoint(tempNext)) {
direct
=
direct
.next(tempNext);
next
=
direct
.nextPoint(
next
);
}
else
{
next
= tempNext;
}
next
.setVal(String.
valueOf
(i));
map
.put(key(
next
),
next
);
//
记录走过的点
}
}
//
打印走过的点
public
void
print() {
for
(
int
y = 1; y <
size
+ 1; y++) {
for
(
int
x = 1; x <
size
+ 1; x++) {
String
temp =
" "
+
(containsPoint(
new
Point(x, y)) ?
map
.get(key(x,
y))
.getVal()
:
" "
);
System.
out
.print(temp.substring(temp.length()
- 5));
}
System.
out
.println(
""
);
}
}
private
String key(Point point) {
return
key(point.getX(), point.getY());
}
private
String key(
int
x,
int
y) {
String
xVal =
"00000"
+ x;
String
yVal =
"00000"
+ y;
return
xVal.substring(xVal.length() - 3)
+
yVal.substring(yVal.length() - 3);
}
private
boolean
containsPoint(Point point) {
return
map
.containsKey(key(point));
}
public
static
void
main(String[] args) {
//
指定范围、起始点、起始方向
Snake
snake =
new
Snake(6,
new
Right(6),
new
Point(1, 1,
"1"
));
snake.run();
snake.print();
}
}
到此,如果只给出
Snake
的属性和关键方法(
run,print
)的实现就可以表达你的设计意图了,其他的只不过是实现细节而已。
为什么这么实现,首先我觉得是自然,至于有什么好处当时还没有想过。看看这句就非常达意:
Snake
snake = new
Snake(6, new
Right(6), new
Point(1, 1, "1"
));
对蛇指定范围、起始方向、起始点才能让蛇开始游走。从这里我们也可以知道,对于蛇来讲只要你告诉它这几个输入,它就知道怎么做了,其他的你不用管。
这样设计有什么好处呢?从题目来看,用户只不过想在一个矩阵上打印一些数字序列。我们知道用户的想法最不可靠了。更多的想法如下:
1
、还可以从四个角开始顺时针内旋;
2
、分别可以从四个角逆时针内旋;
3
、还可以这样:
1 2 3 4 5 6
12
11 10 9 8 7
13
14 15 16 17 18
24
23 22 21 20 19
25
26 27 28 29 30
36
35 34 33 32 31
4
、在单数的序列上用红色字体:
1
2 3
4 5
6
20
21
22 23
24 7
19
32 33
34 25
8
18
31
36 35
26 9
17
30 29
28 27
10
16
15
14 13
12 11
;
5
、
...........
其中:
关于第一个想法,我们一开始就认为是顺时针内旋的,只要正确的初始化起始点和起始方向就可以轻松满足用户需求:
Snake
snake
= new
Snake(6, new
Down(6), new
Point(6,1, "1"
));
Snake
snake
=
new
Snake(6,
new
Left(6),
new
Point(6,6,
"1"
));
Snake
snake
=
new
Snake(6,
new
Up(6),
new
Point(1, 6,
"1"
));
关于第二、三个想法,因为我们有
Direction
为抽象类,根据需要重写子类即可。
关于第四个想法,我想这个工作应该由蛇来做,你(蛇)到那个点上爱干嘛就干嘛,不关方向什么事。
所以好处是:
1
、第一、二、三个需求的变化是通过继承和扩展而不是修改来达到增加功能的目的,最大限度地保护
Snake
类的代码不受冲击。
2
、现在我们有很多各种各样“走法”的功能了,现在有点点变化就是想给数字加上颜色。我们不可能针对每种走法都进行修改吧。因为这个职责很自然地分配给了
Snake
,所以我们就只要修改
Snake
即可,同样其他代码得到保护。
下面是
Direction
子类实现示例:
class
Right
extends
Direction {
public
Right(
int
size) {
this
.
size
= size;
}
public
Direction next(Point point) {
return
new
Down(
size
);
}
public
Point nextPoint(Point p) {
return
new
Point(p.getX() + 1, p.getY());
}
public
boolean
isOut(Point point) {
return
point.getX() >
size
;
}
}
class
Down
extends
Direction {
public
Down(
int
size) {
this
.
size
= size;
}
public
Direction next(Point point) {
return
new
Left(
size
);
}
public
Point nextPoint(Point p) {
return
new
Point(p.getX(), p.getY() + 1);
}
public
boolean
isOut(Point point) {
return
point.getY() >
size
;
}
}
class
Left
extends
Direction {
public
Left(
int
size) {
this
.
size
= size;
}
public
Direction next(Point point) {
return
new
Up(
size
);
}
public
Point nextPoint(Point p) {
return
new
Point(p.getX() - 1, p.getY());
}
public
boolean
</spa
分享到:
相关推荐
这篇博客文章“从一道Neusoft题中想到的Java日志API”可能涉及了在面试或实际项目中遇到的日志相关问题,以及如何通过Java的日志API来解决这些问题。 Java的日志API主要包括以下几个主要库: 1. **java.util....
最近群里有人发了下面这题: 实现一个函数,运算结果可以满足如下预期结果: add(1)(2) // 3 add(1, 2, 3)(10) // 16 add(1)(2)(3)(4)(5) // 15 对于一个好奇的切图仔来说,忍不住动手尝试了一下,看到题目首先想到...
面试题通过一道题考一个专类方面的能力。说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由4个方面组成:Java编程语言、Java类文件格式、Java虚拟机和Java应用程序接口(Java API)。从...
面试题通过一道题考一个专类方面的能力。说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由4个方面组成:Java编程语言、Java类文件格式、Java虚拟机和Java应用程序接口(Java API)。从...
本文讨论了一道常见的笔试面试题目:从10亿个浮点数中找出最大的1万个。这个问题看似简单,但实际上却具有很高的难度,因为处理如此大量的数据需要考虑内存和性能问题。 首先,我们可以想到的方法是建立一个数组把1...
leetcode面试-腾讯专题做题记录 LeetCode腾讯专题地址, 小目标 每天至少一道算法题 每天更新README学习markdown写法(不会真的有人不会markdown吧,不会吧,不会吧) 先这样,有什么想到的再说 1月20日 正式开始,...
阿里巴巴面试题leetcode CharSimpleAlgorithm 字符串算法 WordConversion 该类是用于改变字母的大小写,使一...ps:该类的实际意义没有想到,是我在浏览LeetCode评论区的时候看到的一道阿里巴巴面试题,所以就实现了一下
链表反转是常见的面试题,主要考察程序员对基本数据结构的操作能力和逻辑思维能力。这里我们将详细讨论两种链表反转的方法。 首先,我们来看最常用的一种方法,即迭代法。迭代法的基本思想是使用三个指针pre、cur和...
PS:据说这是迅雷的一道面试题,不过问题本身具有很强的真实性,所以本文打算按照真实场景来考虑,而不局限于面试题的理想环境。首先,我们用一张用户积分表user_score来保存用户的积分信息。表结构:示例数据:下面...
这是一道面试题,要求是这样的: 只使用一个for循环输出下面图形: 如果可以使用2个for(即嵌套循环的话),那这题就很简单了。 但只能用一个for,这可把我想得,想到面试都结束了没想出来。 后来使用String对象,可以...
有一道面试题: Python中如何处理中文问题,能想到的就是以下几方面来规避: 1. 首行添加 # coding = utf-8 # coding = utf-8 # 或者 # -*- coding:utf-8 -*- 2. 字符串前添加u >>> s = u'中文' >>> print(s) 中文 3...
去某公司(公司名不说了,人这套题说不定还要用)面试,现场30分钟做了一套题,其中有一道是这样的: 要求用js写一个函数,对传入的形如下网址字符串,返回对应的对象。 如: 若传入字符串a=’?name=zhiyelee&blog=...
8. 这是一个事件逻辑顺序的排列题,描述了一个产品从出现问题到重新获得市场认可的过程,涉及产品质量、客户反馈、企业改正、采用新方法和重返市场等步骤。 9. 这是一道诗词对联题,需要找出与"江流天地外,山色...
春节的时候去面试了一家公司,笔试题里面有一道是使用简单的代码实现线程的‘死锁’,当时没有想到这道题考的是Synchronized关键字,于是自己定义了两个资源模拟了一下。后面想想肠子都悔青了,于是自己在电脑上...