一道简单的阶层面试题
2015-07-09 21:13
441 查看
首先声明:这篇是我转载而来,无意中看到很有感触:编程需要的是严谨的思维方式,草草了事得到的也只有草草的结果。
无论是技术笔试还是面试,通常会要求写一点代码或详细描述程序思路,很多应试者都认为自己的回答还算过得去,但往往还是没有了下文。究其原因,既有对试题的轻视,也有平时没有养成良好的思维习惯。其实无论试题的难易程度如何,其背后都可以考核出很多知识点来,比如我们来看这样一道简单的笔试题:
写程序,能够计算组合数
。
这道题太简单了,当我们第一次学程序设计语言的时候可能都写过这个程序,我们一起来看一下这道题的思路过程。
首先想到的是写一个求阶乘的函数,然后再另一个函数中对其调用以计算该组合数。这个思路没有问题,但是能写好代码也不是件容易的事,而且我们应该意识到,招聘方的这道简单的问题很显然是需要我们尽量写得完整的,而不是象征性写出思路,因此,必要的健壮性是要体现出来的。很多人的程序如下:
privatestaticint factorial(int
n){
int ret=1;
for(int i=2;i<=n;ret*=i++);
return ret;
}
publicstaticint combination1(int
all,int select){
return
factorial(all)/factorial(select)/factorial(all-select);
}
在这段程序中,由于没有任何容错机制,所以肯定是得不到高分的。另外还有个别人在第二个函数中的语句写成了:
return
factorial(all)/factorial(select)*factorial(all-select);
这样粗心的错误直接会被判0分,基本上就不会再进入下一轮了。
加入了容错检查的程序如下:
privatestaticint factorial(int
n){
if (n<0)
thrownew InvalidParameterException();
int ret=1;
if (n==0 || n==1)
return ret;
else
for(int i=2;i<=n;ret*=i++);
return ret;
}
publicstaticint combination1(int
all,int select){
if (select>all || all<=0 || select<=0)
thrownew InvalidParameterException();
if (select==all)
return 1;
return
factorial(all)/factorial(select)/factorial(all-select);
}
这样这个基本思路的代码就算差不多了,这道题的及格分也就够了。
但是,在众多及格分的成绩中要想获得机会,还是需要再继续改进的。也有的是面试官不断的提出新的需求,比如:如果保持程序中使用int类型不变,那么上述阶乘的计算函数只能算到大约12!,还能进一步提高这个数值吗?或者如果让你提高这段代码的运行效率,你要用什么思路优化?
类似这样问题的提出,就是考验应聘者的时候了,经过分析,优化的空间可以通过原表达式约分实现。在原表达式中,必然有一部分阶乘是重复计算的,而且n!决定了可计算的最大值,如果能把这些重复的计算去掉,把阶乘运算去掉,很显然不仅效率能提高,而且可计算的范围也将变大。
参考程序如下:
publicstaticint combination2(int
all,int select){
if (select>all || all<=0 || select<=0)
thrownew InvalidParameterException();
int ret=1;
int begin=0;
if (all==select)
return ret;
//从1-begin之间的数被约分掉以简化计算
if (select<all-select)
begin=all-select+1;
else
begin=select+1;
for(int i=begin;i<=all;ret*=i++);
//计算分子
for(int i=all-begin+1;i>1;ret/=i--);
//被分母除
return ret;
}
如果能第一次就写成这种思路,很显然,我们的机会会更多。
再来接受一下考验,如果面试官要求你再提供思路来优化运行效率,这时我们还要继续思考,比如把已经运算的结果缓冲起来,当再有相同的参数要求运算时直接从缓冲区返回算好的结果,将比重新运算要快。利用该思路,我们改造上边的函数,形成如下代码:
privatestatic Map<String,Integer>
mapTable=new HashMap<String,Integer>();
……
publicstaticint combination3(int
all,int select){
if (select>all || all<=0 || select<=0)
thrownew InvalidParameterException();
int ret=1;
int begin=0;
if (all==select){
return ret;
}
String tableKey=new String(all+","+select);
Integer tableValue=mapTable.get(tableKey);
if (tableValue!=null)
return tableValue.intValue();
if (select<all-select){
begin=all-select+1;
}
else{
begin=select+1;
}
for(int i=begin;i<=all;ret*=i++);
for(int i=all-begin+1;i>1;ret/=i--);
mapTable.put(tableKey, Integer.valueOf(ret));
return ret;
}
利用一个Map作为缓冲区以保存曾经计算好的结果,典型的空间换时间的思路,但已经能让面试官满意的了。
阶层运算能考虑到这么多,确实非常厉害
无论是技术笔试还是面试,通常会要求写一点代码或详细描述程序思路,很多应试者都认为自己的回答还算过得去,但往往还是没有了下文。究其原因,既有对试题的轻视,也有平时没有养成良好的思维习惯。其实无论试题的难易程度如何,其背后都可以考核出很多知识点来,比如我们来看这样一道简单的笔试题:
写程序,能够计算组合数
。
这道题太简单了,当我们第一次学程序设计语言的时候可能都写过这个程序,我们一起来看一下这道题的思路过程。
首先想到的是写一个求阶乘的函数,然后再另一个函数中对其调用以计算该组合数。这个思路没有问题,但是能写好代码也不是件容易的事,而且我们应该意识到,招聘方的这道简单的问题很显然是需要我们尽量写得完整的,而不是象征性写出思路,因此,必要的健壮性是要体现出来的。很多人的程序如下:
privatestaticint factorial(int
n){
int ret=1;
for(int i=2;i<=n;ret*=i++);
return ret;
}
publicstaticint combination1(int
all,int select){
return
factorial(all)/factorial(select)/factorial(all-select);
}
在这段程序中,由于没有任何容错机制,所以肯定是得不到高分的。另外还有个别人在第二个函数中的语句写成了:
return
factorial(all)/factorial(select)*factorial(all-select);
这样粗心的错误直接会被判0分,基本上就不会再进入下一轮了。
加入了容错检查的程序如下:
privatestaticint factorial(int
n){
if (n<0)
thrownew InvalidParameterException();
int ret=1;
if (n==0 || n==1)
return ret;
else
for(int i=2;i<=n;ret*=i++);
return ret;
}
publicstaticint combination1(int
all,int select){
if (select>all || all<=0 || select<=0)
thrownew InvalidParameterException();
if (select==all)
return 1;
return
factorial(all)/factorial(select)/factorial(all-select);
}
这样这个基本思路的代码就算差不多了,这道题的及格分也就够了。
但是,在众多及格分的成绩中要想获得机会,还是需要再继续改进的。也有的是面试官不断的提出新的需求,比如:如果保持程序中使用int类型不变,那么上述阶乘的计算函数只能算到大约12!,还能进一步提高这个数值吗?或者如果让你提高这段代码的运行效率,你要用什么思路优化?
类似这样问题的提出,就是考验应聘者的时候了,经过分析,优化的空间可以通过原表达式约分实现。在原表达式中,必然有一部分阶乘是重复计算的,而且n!决定了可计算的最大值,如果能把这些重复的计算去掉,把阶乘运算去掉,很显然不仅效率能提高,而且可计算的范围也将变大。
参考程序如下:
publicstaticint combination2(int
all,int select){
if (select>all || all<=0 || select<=0)
thrownew InvalidParameterException();
int ret=1;
int begin=0;
if (all==select)
return ret;
//从1-begin之间的数被约分掉以简化计算
if (select<all-select)
begin=all-select+1;
else
begin=select+1;
for(int i=begin;i<=all;ret*=i++);
//计算分子
for(int i=all-begin+1;i>1;ret/=i--);
//被分母除
return ret;
}
如果能第一次就写成这种思路,很显然,我们的机会会更多。
再来接受一下考验,如果面试官要求你再提供思路来优化运行效率,这时我们还要继续思考,比如把已经运算的结果缓冲起来,当再有相同的参数要求运算时直接从缓冲区返回算好的结果,将比重新运算要快。利用该思路,我们改造上边的函数,形成如下代码:
privatestatic Map<String,Integer>
mapTable=new HashMap<String,Integer>();
……
publicstaticint combination3(int
all,int select){
if (select>all || all<=0 || select<=0)
thrownew InvalidParameterException();
int ret=1;
int begin=0;
if (all==select){
return ret;
}
String tableKey=new String(all+","+select);
Integer tableValue=mapTable.get(tableKey);
if (tableValue!=null)
return tableValue.intValue();
if (select<all-select){
begin=all-select+1;
}
else{
begin=select+1;
}
for(int i=begin;i<=all;ret*=i++);
for(int i=all-begin+1;i>1;ret/=i--);
mapTable.put(tableKey, Integer.valueOf(ret));
return ret;
}
利用一个Map作为缓冲区以保存曾经计算好的结果,典型的空间换时间的思路,但已经能让面试官满意的了。
阶层运算能考虑到这么多,确实非常厉害
相关文章推荐
- 面试题26 复杂链表的复制
- 【剑指offer 面试题34】丑数
- 面试题精选
- mianshi_experience
- 对程序员非常重要的20个软技能
- 黑马程序员 面向对象 static main
- 博士生之“初次面试”
- 《C程序员:从校园到职场》出版预告(5):一种情怀,几分感悟
- 黑马程序员----牛叉的集合之List
- 黑马程序员——Java 面向对象(上)
- 浅谈Android移动开发程序员的职业发展之路
- (剑指Offer)面试题12:打印1到最大的n位数
- iO开发工程师面试题--高级
- Hibernate面试知识点总结
- 程序员求职渠道总结
- 多线程之--google面试题
- 阿里内核电话面试
- 代码农民从做事情的经验
- 黑马程序员——接口
- 黑马程序员——泛型-整理笔记