• 创新工场笔试题整理


    【作者按】网上搜集的题目,自己整理了一下,写了个解答,所有程序均在VS2010上调试通过!
    如果各位看官有更好更高效更巧妙的方法,请不吝指教!

    【一】三道题程序题,要求一个小时做完,而且提前交卷有加分。
    题目1:把一串英文句子按单词反序输出。如:"good moring" -> "moring good"。
    题目2:输入一个正整数N,输出大于N且最接近这个数的素数。
    题目3:用数组实现排序二叉树。
    【出处】http://mcs.sysu.edu.cn/user/longt/Article_1790

    【一解】
    题目1:我的想法是把句子的每个字符遍历一遍,找到每个单词首字母的位置,然后再倒过来访问。

    存放单词首字母序号的结点定义
    struct Node
    {
    Node(
    int n, Node * p = NULL) {i = n; next = p;}
    int i; // 存放单词首字母序号
    Node * next;
    };
    句子反序输出
    char* reverse (char* sentence)
    {
    int i =0;
    Node
    * first = NULL;
    if (sentence != NULL && sentence[0] !='\0')
    {
    first
    =new Node(0, NULL); // 判断内存是否申请成功语句此处略去
    }
    // 遍历寻找每个单词首字母
    while (sentence[i] !='\0')
    {
    if (sentence[i] =='')
    // 前端插入
    first =new Node(i+1, first); // 判断内存是否申请成功语句此处略去
    i++;
    }

    char* r =newchar[i+1];
    Node
    * p = first;
    int n =0;
    while (p != NULL)
    {
    for (int j=p->i; j<i; j++,n++)
    {
    r[n]
    = sentence[j];
    }
    r[n
    ++] ='';
    i
    = p->i -1;
    p
    = p->next;
    }
    r[n
    -1] ='\0'; // 字符串结束符
    return r;
    }


    题目2:我的想法是写一个质数判断函数,然后从N+1往后开始寻找。感觉应该有更佳的方法。

    判断一个数是否是质数
    #include <cmath>
    usingnamespace std;

    // 判断一个数是否是质数
    bool IsPrimeNumber(int n)
    {
    if (n ==2)
    returntrue;
    if (n %2==0|| n <3)
    returnfalse;
    int end = (int)sqrt((float)n); // 不写在for循环判断中,提高效率
    for (int i=3; i<=end; i=i+2)
    {
    if (n % i ==0)
    returnfalse;
    }
    returntrue;
    }
    寻找比N大的最小质数
    int SearchPN(int n)
    {
    while (IsPrimeNumber(n+1) ==false)
    n
    ++;
    return n+1;
    }


    题目3:我不知道用数组实现“排序二叉树”和“实现二叉树”有什么区别。我觉得如果是用数组实现二叉树的话还是很简单的,就是开一个数组,数组中每个元素存放一个树结点,每个树结点包含有“parent”、“leftchild”和“rightchild”三个int。
    以下摘自原文作者:“思路: 一颗树中每个结点只有唯一一个父亲,而数组中每个元素只能存一个值,所以把这个值存为父亲结点,根节点值定-1就好。但是要求实现排序二叉树,所以还需要记录每个结点,因此用个pair<T,T>,最后通过数组pair<T,T> tree[] 来实现。” 



    【二】请问下面这个程序输出是什么?

    #include <stdio.h>

    union A
    {
    int i;
    char c[2];
    };

    int main()
    {
    A a;
    a.c[
    0] =10;
    a.c[
    1] =1;
    printf(
    "%d", a.i);
    return0;
    }

    【出处】http://topic.csdn.net/u/20101012/21/3aa793bb-c8e5-49c7-b72f-ca985b0d5c4e.html?32141

    【二解】union A开辟了一个4字节的空间,如果是x86的电脑,那么是按小端格式(Little-endian)存储数据的,那么A.c[0]指向的就是i的最后一个字节。举列来说:如果我给A.i赋值为10,那么实际内存中是这么存储的:
    (关于何为小端格式,请参见http://www.cnblogs.com/passingcloudss/archive/2011/05/03/2035273.html

    地址  0    1    2    3
    数据  0x0A  0x00  0x00  0x00
    c[0]=0x0A,c[1]=0x00,c[2]=0x00,c[3]=0x00;

    对于未赋值的字节块,编译器在调试版本(DEBUG)会自动填充0xCC,因此本题涉及的内存实际上是这样的:
    地址  0    1    2    3
    数据  0x0A  0x01  0xCC  0xCC

    最终输出结果应该是0xCCCC010A=-859045622。
    这里再重申一下,该结果是在x86电脑的DEBUG模式下的输出! 

    一个诡异的发现,如果把程序改为:

    #include <stdio.h>
    union
    {
    int i;
    char c[2];
    }A;
    void main()
    {
    A.c[
    0]=10;
    A.c[
    1]=1;
    printf(
    "%d", A.i);
    }

    输出结果是0x0000010A=266! 

    引申:通过这道题的方法,我们可以判断CPU是小端格式还是大端格式!


    【三】笔试题量很小,答题时间1个小时。1道填空题,9道左右选择题,最后一道编程题。
    题目1:对于int a = 65536 + 1024 + 8 + 1;int b = f(a);执行后b等于多少?

    int f(int x)
    {
    int c =0;
    while(x !=0)
    {
    x
    = x & (x-1);
    c
    ++;
    }
    return c;
    }


    题目2:5个骰子,六个面分别标有1~6,现在将五个同时随机投掷,五个点数之和为下面哪个点的概率最大?

    (A)14  (B)15  (C)17  (D)20

    题目3:请问c等于多少?

    unsigned long c =0;
    char a =0x48;
    char b =0x52;
    c
    = b<<8| a;


    题目4:编程题
    A、B两个量杯,容量分别为M升、N升,现在要用A和B给另一个量杯C盛水K升,C量杯足够大,备用水无限。编程输出每一个步骤三个杯子中的水量。比如:输出(0,0,0), (M,0,0)等。

    【出处】http://polaris1119.iteye.com/blog/769423

    【三解】
    题目1:这个程序就是求二进制数中1的个数,所以答案是4。

    题目2: 
    思路一:先算每个骰子掷出点数的期望值。每面的概率都是1/6,单个骰子的期望为 
    1*1/6 + 2*1/6 + 3*1/6 + 4*1/6 + 5*1/6 + 6*1/6 = 3.5 
    5个骰子相互独立,期望就是3.5*5=17.5,17或18为最接近的点数,选(C)。
    思路二:掷出的点数最小为5,即1+1+1+1+1只有一种可能;掷出的点数最大为30,即6+6+6+6+6也只有一种可能。
    点数的分布应该是中间大、两头小,并且应该是左右对称的,所以最可能的点数应该是(5+30)/2=17.5,选(C)。

    题目3:b<<8是把b向左位移8位,相当于把b乘以2的8次方,得到0x5200;
    再和a位或,由于0x5200的后8位是0,位或运算等效于加法运算,得到c=0x5248=21064。
    引申:如果c不是定义成unsigned long,而是一个小字节的类型,比如c定义成char型,那么c=0x48。

    题目4: 这道题比较复杂,我们先来分析一下思路。首先,不失一般性,不妨设M>N,如果我们能实现 K1=K%N 升,那么只需再用B量杯给C量杯加上 (int)K/N 杯即可。
    设M和N的最大公约数为L,于是,不管我们对M和N进行几次和运算或差运算,得到的数仍是L的倍数。也就是说,不管怎样操作,使用A量杯和B量杯,我们只能得到“L的倍数”升。注意,这只是说,能实现的一定是L的倍数,但不一定每个L的倍数都能实现。
    另一方面,根据数论中的Bezout等式,存在整数a和b,使得aM+bN=L成立。
    事实上,假如我们找到了一组满足a0*M+b0*N=L的(a0,b0),那么对于任意整数t,a=a0+t*N/L,b=b0-t*M/L都能满足aM+bN=L。
    所以,我们一定能找到一组a>0、b<0,使aM+bN=L,那么我们只需往C量杯中倒入a杯A量杯的水,再倒走(-b)杯B量杯的水,C量杯中就能得到L升水!

    结合上面两方面,我们得到,C量杯能实现K升水 当且仅当 K1是L的自然数倍。

    具体实现的思路如下:先求出M和N的最大公约数L,判断K1是否能够整除L;然后不断给C倒入M升水(中途如果C水量超过N,就倒走N升水),直到C水量为K1;最后再给C中倒入若干次N升水即可。
    具体代码如下: 

    打印每次操作
    void Show(int&i, int A, int B, int C) // i记录操作的次数
    {
    cout
    << i <<".("<< A <<","<< B <<","<< C <<")"<< endl;
    i
    ++;
    }
    辗转相除法求最大公约数
    int GCD(int M, int N) // 辗转相除法求最大公约数
    {
    if (M >= N)
    {
    if (M%N ==0)
    return N;
    else
    return GCD(M%N, N);
    }
    else
    {
    if (N%M ==0)
    return M;
    else
    return GCD(M, N%M);
    }
    }
    解法主函数
    bool Solution(int M, int N, int K)
    {
    // M, N, K是三个容器的容量
    // A, B, C是三个容器目前的水量
    int A=0, B=0, C=0, i=1;
    int K1 = K % N;
    int L = GCD(M, N);
    if (K1%L !=0) // 不可能实现
    returnfalse;
    while (C != K1)
    {
    // A中盛满水倒给C
    A = M;
    Show(i, A, B, C);
    C
    += A; A =0;
    Show(i, A, B, C);
    // 如果C水量超过N,就倒走N
    while (C > N)
    {
    B
    = N; C -= N;
    Show(i, A, B, C);
    B
    =0;
    Show(i, A, B, C);
    }
    }
    // 给C倒上若干杯B中的水
    while (C != K)
    {
    B
    = N;
    Show(i, A, B, C);
    B
    =0; C += N;
    Show(i, A, B, C);
    }
    returntrue;
    }

    事实上,这个实现方法不是很完美,比如M=5,N=4,K=10,本来只需用2杯A量杯的水即可;但是按照上述算法,是倒入一杯A量杯的水,随后立即倒走一杯B量杯的水,如此往复10次,得到10升,这显然是不明智的。其实可以在程序中加以改进,只需在每准备倒出一杯B量杯的水时判断一下:现在C中的水量离K升是不是差M的整数倍即可。

    解法主函数(改进)
    bool Solution(int M, int N, int K)
    {
    // M, N, K是三个容器的容量
    // A, B, C是三个容器目前的水量
    int A=0, B=0, C=0, i=1;
    int K1 = K % N;
    int L = GCD(M, N);
    if (K1%L !=0) // 不可能实现
    returnfalse;
    while (C != K1)
    {
    // A中盛满水倒给C
    A = M;
    Show(i, A, B, C);
    C
    += A; A =0;
    Show(i, A, B, C);
    // 如果C水量超过N,就倒走N
    while (C > N)
    {
    if ((K-C)%M ==0) // 改进点
    break;
    B
    = N; C -= N;
    Show(i, A, B, C);
    B
    =0;
    Show(i, A, B, C);
    }
    if ((K-C)%M ==0) // 改进点
    break;
    }
    if ((K-C)%M ==0)
    {
    // 给C倒上若干杯A中的水,改进点
    while (C != K)
    {
    A
    = M;
    Show(i, A, B, C);
    A
    =0; C += M;
    Show(i, A, B, C);
    }
    }
    else
    {
    // 给C倒上若干杯B中的水
    while (C != K)
    {
    B
    = N;
    Show(i, A, B, C);
    B
    =0; C += N;
    Show(i, A, B, C);
    }
    }
    returntrue;
    }

    这样的算法就比较完美了!

    【四】一些小题目

    题目1:路由器与交换机的区别。

    题目2:进程与线程的差别:
    A、操作系统只调度进程,不调度线程
    B、线程共享内存地址空间,进程不共享
    C、线程间可以共享内存数据,但进程不可以
    D、进程间可以通过IPC通信,但线程不可以

    题目3:下面排序算法的时间复杂度不是O(nlogn)的是:
    A、二分法插入排序  B、快速排序  C、归并排序  D、堆排序

    题目4:利用KMP算法实现字符串匹配。

    题目5:某工作有5道工序,某个工作不能在最后做,请问有多少种工作情况。

    题目6:内存中有3页,初始为空,页面走向为4,3,2,1,4,3,5,4,3,2,1,5,分别使用先进先出,最近最少使用,理想页面置换算法,请问缺页次数是多少?

    题目7:TCP具有但UDP不具有的特点不包括:
    A、对上层应用而言,收到数据包的顺序与对方发送的顺序一致
    B、源IP、目的IP均相同的数据包经过同样的路由路径
    C、传输过程中个别数据包丢失,接收端存在检测机制
    D、传输数据前必须使用握手方式建立连接

    题目8:下面程序的输出结果是什么?

    #include <stdio.h>
    int func(int n)
    {
    if(n==0)
    return3;
    else
    return (func(n-2)+func(n-1));
    }
    void main()
    {
    printf(
    "%d\n", func(13));
    }

    【出处】http://hi.baidu.com/g882/blog/item/5142211f3d1d2efae0fe0b94.html

    【四解】

    题目1:路由器和交换机的区别
    [1]工作层次不同:交换机是工作在OSI/RM开放体系结构的数据链路层(即第二层),而路由器工作在OSI模型的网络层(即第三层)。
    [2]转发所依据的对象不同:交换机是利用物理地址或者说MAC地址来确定转发数据的目的地址;而路由器则是利用不同网络的ID号(即IP地址)来确定数据转发的地址。 
    [3]传统的交换机只能分割冲突域,不能分割广播域;而路由器可以分割广播域。
    [4]路由器提供了防火墙的服务,而交换机则没有。 
    参考:http://network.51cto.com/art/200806/78135.htm 

    题目2:
    选项A:线程有两种传统的控制模式:用户级线程和内核级线程,前者对于操作系统内核是不可见的,而对于后者,内核了解每一个作为可调度实体的线程。所以内核级线程可被操作系统调度。A错!
    选项B:正确!
    选项C:进程间虽然不能共享内存地址空间,但是把内存数据复制一份,达到共享数据的目的。 C错!
    选项D:进程间通过IPC通信,线程间可以直接读写进程数据段(如全局变量)来进行通信。D错! 

    题目3:各种排序复杂度总结如下:
    O(n^2):冒泡排序、选择排序、插入排序
    O(nlogn):堆排序、快速排序
    O(n):归并排序
    本题选择(A)。

    题目4:略。

    题目5:没有限制“某个工作不能在最后做”的情况下共有 5!=120 种工作方案,去除“某个工作在最后做”的情况 4!=24 种工作方案,最后得到96种工作方案。

    题目6:
    (1)先进先出:4,3,2,1(miss),4(miss),3(miss),5(miss),4,3,2(miss),1(miss),5。
           缺页次数6次。
    (2)最近最少使用:4,3,2,1(miss),4(miss),3(miss),5(miss),4,3,2(miss),1(miss),5(miss)。
           缺页次数7次。
    (3)理想页面置换算法:4,3,2,1,4,3,5,4,3,2,1,5



     

    本文作者:清风行云
    目前我开通了新博客,最新的内容和资讯都会第一时间在新博客发布,欢迎关注我的新博客 iFreeThinking.com ! 
    本文版权归 清风行云博客园 共有,欢迎转载!但未经作者同意,必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利!
  • 相关阅读:
    Atitit sumdoc everything index tech and index log 目录 1. 使用的tech 1 1.1. Atitit 日志记录的三个trace跟踪等级文件夹级
    Atitit nlp用到的技术与常见类库 目录 1. 常用的技术 1 1.1. 语言处理基础技术 分词 相似度等 1 1.2. 新闻摘要 2 1.3. 情感倾向分析 2 1.4. 文章标签 2 1.
    Atitit 资源类型的分类法规范MIME类型类型 目录 1.1. 一个MIME类型至少包括两个部分:一个类型(type)和一个子类型(subtype)。 1 1.2. 命名格式MIME类型包括一个
    Atitit 六种知识表示法 目录 1. 知识的静态描述和动态描述 1 1.状态空间表示 以状态和运算符(operator) 1 2.问题归约表示(函数式?? 1 (1)一个初始问题描述; 2 (2)
    微信小程序登录流程总结 目录 1.1. 前端调用wx.login 。。给后端传递一个code 1 1.2. 开发者需要在开发者服务器后台调用 auth.code2Session,使用 code 换取
    Atititi 计算机系 教材 目录 1. 硬件类 2 1.1. 《微机系统与接口技术》 2 1.2. 《计算机组成与系统结构(第2版)》 2 2. Atitit 操作系统原理 操作系统原理(cpu
    Atitit 声音和音乐检索 多媒体信息检索 信息检索 目录 1.1. 14.4.5 音频基础知识 1 1.2. 多媒体信息检索的方法主要有哪些?其原理是什么? 1 1.3. 基于文本的检索和基于
    Atitit 信息检索 v3 t55.docx Atitit 现代信息检索 目录 1.1. 信息检索(索引 索引 结构化文本 1 1.2. Atitit 重要章节 1 1.3. 息检索建模 1 1.
    Atiitt 程序语言vm与rt 虚拟机与运行时 目录 1. 运行时 虚拟机的一种,一般指进程级别的虚拟机。 1 1.1. 线程模型 1 1.2. 堆栈机vs 寄存器 1 1.3. 存储模型 2 1
    Atiitt 图像处理的常见功能业务用途与类库与功能实现 目录 1. 常见业务场景 3 1.1. 缩略图 蒙版遮罩挖空 3 1.2. 区域裁剪,水印,旋转 3 1.3. 判断图像大小分辨率要求
  • 原文地址:https://www.cnblogs.com/passingcloudss/p/2034209.html
Copyright © 2020-2023  润新知