- 浏览: 28203 次
- 性别:
- 来自: 深圳
最新评论
-
hpzxyj:
${riskLevelMap[fn:length(riskle ...
如何用jstl标签将number类型转换为String类型? -
ilove2009:
pouyang 写道我正好遇到这样的情况
<c:out ...
如何用jstl标签将number类型转换为String类型? -
pouyang:
我正好遇到这样的情况<c:out value=" ...
如何用jstl标签将number类型转换为String类型? -
sav2005:
确实很强啊~~佩服
从一道面试题想到的 -
bill600:
看看同道的讨论 觉着很有意思 我也弄一个试试
思路很简单
把 ...
从一道面试题想到的
最近在 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
评论
不知道该说什么。
有人说有意义,有人说没意义。
如果是应聘,这样的代码可能在有效时间里无法实现。
但是对于学习JAVA的人来说,确实应该重视起来。
OO思想。
对于某些人的简单问题复杂化???真的不想说什么了!
public class PrintSquare {
private int sideLength = 1;
private String[][] elementList;
private static final String GO_RIGHT = "right";
private static final String GO_DOWN = "down";
private static final String GO_LEFT = "left";
private static final String GO_UP = "up";
PrintSquare() {
}
PrintSquare(int sideLength) {
this.sideLength = sideLength;
elementList = new String[sideLength][sideLength];
}
public void printSquareToConsole() {
int num;
int column = 0;
int row = 0;
String mark1 = GO_RIGHT;
for (num = 0;num < sideLength * sideLength;num++) {
elementList[row][column] = String.valueOf(num);
if ((mark1) == GO_RIGHT) {
column++;
if (column == sideLength || elementList[row][column] != null) {
column--;
row++;
mark1 = GO_DOWN;
}
} else if ((mark1) == GO_DOWN) {
row++;
if (row == sideLength || elementList[row][column] != null) {
column--;
row--;
mark1 = GO_LEFT;
}
} else if ((mark1) == GO_LEFT) {
column--;
if (column == -1 || elementList[row][column] != null) {
column++;
row--;
mark1 = GO_UP;
}
} else if ((mark1) == GO_UP) {
row--;
if (row == -1 || elementList[row][column] != null) {
column++;
row++;
mark1 = GO_RIGHT;
}
}
}
for (int i = 0;i < this.sideLength;i++) {
for (int j = 0;j < this.sideLength;j++) {
System.out.print(elementList[i][j]);
}
System.out.println();
}
}
public static void main(String[] args) {
PrintSquare ps = new PrintSquare(3);
ps.printSquareToConsole();
}
}
static void populateArray(int minValue, int rowNum, int colNum, int[][] toBePopulatedArray) {
for (int colIdx = 0; colIdx < colNum; colIdx++) {
toBePopulatedArray[0][colIdx] = minValue++;
}
//Recursive population
if (rowNum > 1 || colNum > 1) {
int newRowNum = colNum;
int newcolNum = rowNum - 1;
int[][] subArray = new int[newRowNum][newcolNum];
populateArray(minValue, newRowNum, newcolNum, subArray);
for (int colIdx = colNum - 1; colIdx > -1; colIdx--) {
for (int rowIdx = 1; rowIdx < rowNum; rowIdx++) {
toBePopulatedArray[rowIdx][colIdx] = subArray[newRowNum - colIdx - 1][rowIdx - 1];
}
}
}
}
这个是我见过最OO的算法了
OO不是要多建类.
而是要有一个现实中可以对应的例子
以帮助理解.
这个算法就是对原题的描述.
削土豆可以用来形容这个算法
把已经削下去的部分就不放在数组中了.
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TestArray {
private int index=0;
private Integer[][] array;
public TestArray(){
}
public void doGenerateArray(int ind){
this.index=ind;
int content=1;
array=new Integer[index][index];
if(index>=1){
for(int i=0;i<index;i++){
array[0][i]=content++;
}
int rowIndex=1;
int colIndex=index-1;
for(int i=index-1;i>0;i--){
for(int cir=0;cir<i;rowIndex++,cir++){
array[rowIndex][colIndex]=content++;
}
rowIndex--;
colIndex--;
for(int cir=0;cir<i;colIndex--,cir++){
array[rowIndex][colIndex]=content++;
}
rowIndex--;
colIndex++;
i--;
for(int cir=0;cir<i;rowIndex--,cir++){
array[rowIndex][colIndex]=content++;
}
rowIndex++;
colIndex++;
for(int cir=0;cir<i;colIndex++,cir++){
array[rowIndex][colIndex]=content++;
}
rowIndex++;
colIndex--;
}
}
}
public void doPrintArray(){
StringBuffer s;
Integer outputStr;
if(index>=1){
for(int i=0;i<index;i++){
for(int j=0;j<index;j++){
outputStr=array[i][j];
s=new StringBuffer(5);
s.append(outputStr);
if(outputStr>99&&outputStr<=999){
s.append(" ");
}
if(outputStr>9&&outputStr<=99){
s.append(" ");
}else if(outputStr<=9){
s.append(" ");
}
System.out.print(s.toString());
}
System.out.println("");
}
}else{
System.out.println("这是一个空数组!");
}
}
public boolean isNumeric(String str)
{
Pattern pattern=Pattern.compile("[0-9]*");
Matcher isNum=pattern.matcher(str);
if(!isNum.matches()){
return false;
}
return true;
}
public static void main(String[] args){
TestArray testArray=new TestArray();
String str=null;
InputStreamReader reader=new InputStreamReader(System.in);
BufferedReader bufferReader=new BufferedReader(reader);
System.out.println("请输入矩阵长度,例如5:");
try{
str=bufferReader.readLine();
if(testArray.isNumeric(str)){
testArray.doGenerateArray(Integer.parseInt(str));
testArray.doPrintArray();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
<div class="quote_div">
<div class="quote_title">kingapex 写道</div>
<div class="quote_div">
<p>内螺旋矩阵算法分析<br><a href="http://shuishou119800.iteye.com/blog/549592" target="_blank"><br>http://shuishou119800.iteye.com/blog/549592</a></p>
<p> </p>
</div>
<p> </p>
<p>您访问的地址不存在,请确认您输入的URL地址</p>
</div>
<p> </p>
<p> </p>
<p>连接加错了,不好意思</p>
<p>已纠正</p>
<div class="quote_div">
<p>内螺旋矩阵算法分析<br><a href="%E5%86%85%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5%E7%AE%97%E6%B3%95%E5%88%86%E6%9E%90%20%20http://shuishou119800.iteye.com/blog/549592" target="_blank"><br>http://shuishou119800.iteye.com/blog/549592</a></p>
<p> </p>
</div>
<p> </p>
<p>您访问的地址不存在,请确认您输入的URL地址</p>
<p> </p>
一个对象就看出对oop理解很深了,那我只能说你理解的够浅的了!!-_-
恩,我赞同你的说法,简单问题复杂化。精辟的发表了对文章的看法发表评论
相关推荐
这篇博客文章“从一道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关键字,于是自己定义了两个资源模拟了一下。后面想想肠子都悔青了,于是自己在电脑上...