`

一道笔试题目的算法过程

阅读更多
转贴地址:url
        [url]  http://blog.csdn.net/caowenbin/archive/2011/03/02/6217976.aspx[/url]

无论是技术笔试还是面试,通常会要求写一点代码或详细描述程序思路,很多应试者都认为自己的回答还算过得去,但往往还是没有了下文。究其原因,既有对试题的轻视,也有平时没有养成良好的思维习惯。其实无论试题的难易程度如何,其背后都可以考核出很多知识点来,比如我们来看这样一道简单的笔试题:
写程序,能够计算组合数 。

这道题太简单了,当我们第一次学程序设计语言的时候可能都写过这个程序,我们一起来看一下这道题的思路过程。

首先想到的是写一个求阶乘的函数,然后再另一个函数中对其调用以计算该组合数。这个思路没有问题,但是能写好代码也不是件容易的事,而且我们应该意识到,招聘方的这道简单的问题很显然是需要我们尽量写得完整的,而不是象征性写出思路,因此,必要的健壮性是要体现出来的。很多人的程序如下:
  
 private static int factorial(int n){
       int ret=1;
       for(int i=2;i<=n;ret*=i++);
       return ret;
    }
   
    public static int combination1(int all,int select){
       return factorial(all)/factorial(select)/factorial(all-select);
    }


在这段程序中,由于没有任何容错机制,所以肯定是得不到高分的。另外还有个别人在第二个函数中的语句写成了:
       return factorial(all)/factorial(select)*factorial(all-select);
这样粗心的错误直接会被判0分,基本上就不会再进入下一轮了。

加入了容错检查的程序如下:
   
private static int factorial(int n){
       if (n<0)
           throw new InvalidParameterException();
      
       int ret=1;
       if (n==0 || n==1)
           return ret;
       else
           for(int i=2;i<=n;ret*=i++);
      
       return ret;
    }
   
    public static int combination1(int all,int select){
       if (select>all || all<=0 || select<=0)
           throw new InvalidParameterException();
      
       if (select==all)
           return 1;
      
       return factorial(all)/factorial(select)/factorial(all-select);
    }

这样这个基本思路的代码就算差不多了,这道题的及格分也就够了。

但是,在众多及格分的成绩中要想获得机会,还是需要再继续改进的。也有的是面试官不断的提出新的需求,比如:如果保持程序中使用int类型不变,那么上述阶乘的计算函数只能算到大约12!,还能进一步提高这个数值吗?或者如果让你提高这段代码的运行效率,你要用什么思路优化?
类似这样问题的提出,就是考验应聘者的时候了,经过分析,优化的空间可以通过原表达式约分实现。在原表达式中,必然有一部分阶乘是重复计算的,而且n!决定了可计算的最大值,如果能把这些重复的计算去掉,把阶乘运算去掉,很显然不仅效率能提高,而且可计算的范围也将变大。
参考程序如下:
   
public static int combination2(int all,int select){
       if (select>all || all<=0 || select<=0)
           throw new 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;
    }

如果能第一次就写成这种思路,很显然,我们的机会会更多。

再来接受一下考验,如果面试官要求你再提供思路来优化运行效率,这时我们还要继续思考,比如把已经运算的结果缓冲起来,当再有相同的参数要求运算时直接从缓冲区返回算好的结果,将比重新运算要快。利用该思路,我们改造上边的函数,形成如下代码:
   
private static Map<String,Integer> mapTable=new HashMap<String,Integer>();
……
    public static int combination3(int all,int select){
       if (select>all || all<=0 || select<=0)
           throw new 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作为缓冲区以保存曾经计算好的结果,典型的空间换时间的思路,但已经能让面试官满意的了。

但是,面试官的问题是会一直延续下去的,他思路的过程也应该是我们写代码思路的过程,因此,新的问题可能是:用HashMap不一定能提高效率,反而会降低效率,能说说是什么原因吗?如果不用HashMap,那用什么容器做缓冲区能更高效?
其实,用HashMap,如果像上文程序那样使用String作为Key,则每次检索时的Hash运算都会耗掉很多时间,自然,如果不采用这种额外的寻址算法,才能达到预期的目的。常用的方式就是采用表格,将算好的结果以某种简单的方式存入到表格中,或者如果运算的数据范围在合适的范围内,也可以预先把表格定好,这样就减少了寻址带来的损失了。为了简单起见,下面的代码使用了数组代替前面的Map。
   
private static int[] intTable;
    ……
    public static int combination4(int all,int select){
       if (select>all || all<=0 || select<=0)
           throw new InvalidParameterException();
      
       int ret=1;
       int begin=0;
       if (all==select){
           return ret;
       }
      
       if (intTable!=null && intTable[select]!=-1)
           return intTable[select];
      
       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--);
      
       if (intTable==null){
           intTable=new int[all+1];
           for(int i=0;i<all+1;intTable[i++]=-1);
       }
       intTable[select]=ret;
      
       return ret;
    }


面试官的问题又来了:还能再优化吗?你可以与面试官讨论更多的细节以决定不同的优化方案,也可以如实告诉面试官你没有想到别的办法。我想,这时面试官期待的已经不是你能给他新的代码了,更多的是在考察你有没有独立解决难题这样代码之外的能力了。

对于前文的代码,最后通过对比发现,使用数组缓存的实现其运行效率最高,然后是改良算法2,接下来是阶乘的实现方案,但比combination2要慢上1-2倍,最后是使用HashMap的实现效率最低。

通过上述解析,可以看到,貌似简单的面试题,其实可以考察到很多内容,所以,求职时要认真准备,认真对待



分享到:
评论

相关推荐

    迅雷面试笔试题目

    迅雷面试笔试题目涉及到多个知识点,包括算法、数据结构、编程实现、逻辑推理等。针对提供的内容,我们可以深入分析其中的技术要点。 **1. 数据库查询优化** 题目中提出了一个问题:如何使得90%的查询能在100毫秒...

    DJI大疆2019年8月雷达算法工程师笔试题B卷

    首先,“DJI大疆2019年8月雷达算法工程师笔试题B卷”这一标题说明这是一次面向特定职位(雷达算法工程师)的招聘考试。大疆(DJI)是一家专门从事民用级无人机和航拍技术的制造商,因此笔试内容会涵盖相关专业知识。...

    北京-百度计算机视觉算法工程师笔试-回忆版.pdf

    布丰投针问题是一道经典的数学问题,考察了候选人的数学能力和算法设计能力。可以使用蒙特卡罗方法来解决该问题。 五、计算机视觉相关问题 1. 图像中物体检测算法 图像中物体检测算法是计算机视觉领域中的一个...

    腾讯笔试题目整理(部分)

    腾讯作为中国知名的互联网巨头,其笔试题目历来备受求职者关注,因为这不仅是进入腾讯的一道门槛,也是检验个人技能和素质的重要方式。本压缩包包含了部分年份的腾讯笔试题目,对于准备应聘腾讯的同学来说,这是一个...

    部分外企笔试题目总结

    从给定的文件内容来看,这是一份关于外企笔试题目的总结,涵盖了多个知名跨国公司的面试题目,包括Microsoft、IBM、PWC等。这些题目不仅考验应聘者的专业知识,还涉及逻辑思维、数学能力以及语言表达等多个方面。...

    Java笔试题目 !!!

    Java笔试题目是评估应聘者Java编程能力的重要环节,它涵盖了从基础语法到高级特性的各个方面。...对于“Java笔试题目汇总[一].txt”这样的资料,应当仔细阅读,理解并完成每一道题目,以提升自己的Java编程技能。

    虹软2017年秋招算法岗笔试题

    根据提供的压缩包子文件的文件名称列表,我们可以推测这些是笔试题目的图像文件,可能包含题目、解题过程或者答案示例。具体来说: 1. "6.JPG":可能是一道或几道笔试题的图片,可能涉及到排序算法、搜索算法或其他...

    腾讯的求职之路,详细介绍了腾讯的笔试和面试过程

    腾讯的笔试和面试过程考察了候选人的基础知识、算法基础知识、技术实现能力和项目经验。候选人需要熟练掌握计算机科学的基础知识和算法基础知识,并且需要具备良好的技术实现能力和项目经验。 通过本文的介绍,希望...

    hadoop2面试题 - 2012腾讯笔试的一道算法题.pdf

    ### hadoop2面试题 - 2012腾讯笔试的一道算法题 #### 背景与题目概述 本文档提供了2012年腾讯笔试中一道关于字符串处理的算法题,该题目要求将字符串中的所有大写字母移动到字符串的末尾,同时保持其他字符的相对...

    2020年腾讯实习生算法笔试题目(感触良多)

    这篇文章主要讲述了2020年腾讯实习生算法笔试的体验与其中涉及的算法题目。作者首先表达了对于笔试过程中多目标优化问题的思考,指出在有限时间内合理分配解题时间以达到最大收益的重要性。在实际考试中,可能会遇到...

    程序员面试笔试算法题

    本文档精选了100道程序员笔试算法题,其中一道经典题目是如何将二叉查找树转换为排序的双向链表。 #### 问题描述 给定一个二叉查找树(Binary Search Tree, BST),任务是将其转换为一个排序的双向链表(Doubly ...

    c/c++笔试大全(含答案)

    软件工程题目需要考虑效率、异常问题和设计思路,例如华为的一道关于指针方面的编程题,需要将0移至数组后面,非0整数移至数组前面,并保持有序。 算法设计 算法设计需要考虑到效率和数学性,例如求出用1、2、5三...

    阿里巴巴2015秋招算法类机试题目(三阶魔方)源代码

    【标题】中的“阿里巴巴2015秋招算法类机试题目(三阶魔方)源代码”指的是一次阿里巴巴公司在2015年秋季招聘过程中,针对算法类岗位的在线笔试题目。该题目涉及的核心是编程实现解决三阶魔方的算法,即编写程序来...

    70道常见面试算法笔试题

    这70道常见的面试算法笔试题旨在帮助求职者准备这些关键领域的问题。本问题聚焦于一道具体的算法题——将二元查找树(Binary Search Tree, BST)转化为排序的双向链表(Sorted Doubly Linked List)。下面我们将详细...

    各种笔试题(数据结构,算法)

    ### 笔试题目的范围 #### 数据结构与算法 在IT行业中,数据结构与算法是基础且重要的组成部分。这些笔试题旨在评估应聘者的基础技能以及解决问题的能力。 - **数据结构**:包括数组、链表、栈、队列、树、图等...

    中兴工作的笔试题目(计算机)

    这篇内容是关于中兴软创2008年应届毕业生招聘笔试中的一道C++试题。这道题目考察了考生对C++基础知识的理解,包括字符串处理、指针操作以及基本的算法设计。以下是对该试题的详细分析: 首先,题目要求实现一个名为...

    杭电计算机研究生复试——笔试题目

    在杭电计算机研究生复试的笔试编程题目中,有一道要求将十进制数转换为八进制数的问题。此问题通过循环不断地对数字取模和除以8来实现,每次取模得到的余数即为转换后的数字的某一位,然后除以8更新原数,直到原数为...

    2012谷歌笔试题

    标题与描述中的关键词“2012谷歌笔试题”揭示了这一内容的核心是关于谷歌在2012年招聘过程中使用的笔试题目集。这不仅是对谷歌公司当时招聘流程的一个历史回顾,也是对IT行业求职者准备面试的重要参考资料。下面,...

Global site tag (gtag.js) - Google Analytics