zoukankan      html  css  js  c++  java
  • 小米面经

    昨天下午去武大参加小米的笔试,一共三道题,做得很差。本以为必然没戏了,谁知道早上凌晨1点半来了面试的短信通知。招聘人员真的是辛苦了。

    今天下午一点半,在武汉珞珈山国际大酒店进行面试,题目记录如下:

    1.两个已序数组A,B,将两个数组进行归并,并将结果存放在数组B中,B足够大。例如A={1,3,5},B={2,3,5},结果B={1,2,3,4,5,6}

    答:这一题比较简单。关键在于从尾向头进行赋值,否则可能会覆盖需要的值。代码如下(未调试过)

    void func(int *A,int lenA,int *B,int lenB)
    {
        int m=lenA-1;
        int n=lenB-1;
        for(int i=lenA+lenB-1;i>=0;)
        {
            if(m==0)
            {
                break;
            }
            else if(n==0)
            {
                for(;m>=0;m--)
                {
                    B[i]=A[m];
                    i++;
                }
            }
            else
            {
                if(A[m]>=B[n])
                {
                    B[i]=A[m];
                    m--;
                    i++;
                }
                else
                {
                    B[i]=B[n];
                    n--;
                    i++;
                }
            }
        }
    }

    2.改进昨天笔试中的一道题目:两个数组I1,I2,二者只有一个公共子序列,求之。

    答:一般求最大公共子序列的方法是动态规划,时间复杂度O(mn)(我昨天笔试就是这么做的,结果只得了12分,满分20)。但是这一题说明了只有一个公共子序列,因此不必那么麻烦,只要找出I2中也属于I1的元素就行了。

    这一题我首先想到的是bitmap,因为查找速度很快O(1),但是空间复杂度较高,面试官让我想想能不能把空间复杂度降低,我想到了hashtable.

    首先将I1里的数全部存入hashtable,然后遍历I2,只要该数在hashtable中,证明它是公共子序列中的元素,直接打印出来。这样时间复杂度就是O(n)了。

    代码我就不贴了,比较简单。建议大家也看看bitmap,在处理大数据的搜索时,很有用。

    3.为什么Linux分为内核态和用户进程态?什么时候这二者会进行切换?

    答:这题完全不会,只有硬着头皮答了。在用户进程调用系统函数时,会进入内核态。其他就不知道了。

    后来面试官给我讲了讲这一题:之所以分开,是因为内核态可以操作更多的硬件资源,而且不用用户去关心,如果让用户自己操作,可能会产生许多错误。用户态切内核态有三种情况:1.系统调用,2.异常,3.外围设备中断。感觉这题和底层硬件关系密切。

    一面结束,紧接着是二面。

    二面的问题乍看之下都很难,但是自己思考其实也没那么难,我是在面试官的提醒下才答出来的。感觉不怎么好。

    1.一个数组中有100w个整数,这些整数的范围时1~99999,要求打印出重复的数字。

    答:最先想到的还是bitmap,但是空间复杂度太高。面试官说改进一下,想破头没想出来。最后请求面试官能否告知答案,结果十分之巧妙,估计我自己再多想几个小时也未必想得出。

    解法如下:

    这100w个数据存在一个数组里,每一个数可以让他对应一个位,这叫位图。举例来说,假设第一个数是59,我就让他对应59位,第二个数是63,我就让他对应63位。如果有重复数字,那么也就是说有多个数对应相同的一位。我们在遍历的时候,对位做一个记号,如果碰到有的位已经被记号过了,那证明之前已经有过这个数了。

    具体来说:假设这个数组是A={59,63,46,.....59,.....},第一个数是59,我们就让A[59]=A[59]-1000000,这样A[59]就小于0了,这就是标记。当遍历到第二个59时,我们会再去检查A[59],发现A[59]已经小于0了,因此前面肯定一应有了一个59,使A[59]减了1000000,当遍历到A[59]时,我们去找A[A[59]+1000000]。不知道这么解释清楚没有。

    2.在一定精度内求根号n,n>=1。

    答:一接到这一题,我蒙了。记得以前好像做过这题,我没搞出来,好像方法很复杂,一下没了信心。面试官提示了我一下,可以用二分法,我一下豁然开朗。

    其实就是一个二分查找。代码如下(没测试过):

    float n;
    float e;//精度
    
    float func(float beg,float end)
    {
        float f = (beg+end)/2;
        float f2 = f*f;
        if(f2-n<=e && f2-n>=-e)
        {
            return f;
        }
        else if(f2-n>e)
        {
            return func(beg,f);
        }
        else
        {
            return func(f,end);
        }
    }
    

    3.N个木头和N个石头,木头之间质量两两不同,石头也是。但是木头的质量和石头的质量一一对应,现在给你一个天平,将木头和石头分成质量一一对应。

    答:这一题我都没直接答出来。瞎了。其实很多题目,当你知道答案以后,觉得很简单。因此理解答案对我们来说并不困难,只是我们没有一个很好地方法将思路引向答案。这也与平时我们所受到的教育有关,我们从小到大,受到的都是欧几里得式的教育。即先给出结论,再证明之。我们从来没有去探究怎么想到这个结论的。更详细的内容我推荐大家看看一本书,叫做《暗时间》。

    回到这一题,相信大家已经有答案了。最笨的方法当然是一一对比,时间复杂度为O(n^2),有没有更快的呢?首先,比O(n^2)快一个数量级的时间复杂度是O(nlgn),这不正是比较类排序的下限吗?给了个天平,正好用于比较。因此,我们用时间复杂度为O(nlgn)的排序方式(快排,归并,堆排等)将两堆分别排序即可,排序后就一一对应了。

    至此,面试结束。

    总结一下。感觉小米对算法和思路的要求比较高。我投的是路由器软件研发,居然没有问我TCP/IP的知识。小米的编程语言大部分是Java,但是面试的时候,也没涉及过编程语言的问题。互联网公司对编程语言问题问得一向很少。其实关键在思路,有了思路,用什么语言实现并没很大差。所以完全没必要去纠结什么学C++还是JAVA。

  • 相关阅读:
    021.day21 反射 Class类 反射常用操作
    020.day20 线程概述 多线程优缺点 线程的创建 线程常用方法 生命周期 多线程同步
    019.day19 缓冲流 对象流 标准输入输出流
    018.day18 map集合如何实现排序 File类 IO流 字节流 字符流 编码
    017.day17 Map接口 克隆 treeSet集合排重缺陷
    016.day16 HashSet TreeSet 比较器Comparable Comparator
    015.day15
    014.day14
    013.day13
    线程
  • 原文地址:https://www.cnblogs.com/johnsblog/p/3981849.html
Copyright © 2011-2022 走看看