腾讯后台开发暑期实习 一面&二面总结(附答案)

WLZeaz 来自华南理工大学,最近面试了腾讯wxg的后台开发

欢迎关注他的知乎专栏

原文连接:https://zhuanlan.zhihu.com/p/113968411

    最近面试了腾讯wxg的后台开发岗位,把遇到的题目都总结下来了,希望可以给还在准备实习面试的同学们一点参考,答案的话会慢慢补充。由于答案都是由我根据自己掌握的知识写的,难免有错误或疏漏之处,还望读者们不吝赐教,有什么错误随时可以在评论区留言告诉我。

    整个面试给我最大的感触就是对OS底层知识要求很高,而OS这一块恰恰是我的短板,面试问了好多和Linux相关的问题我答的都不是很好……所以最近准备把《鸟哥的Linux私房菜》这本书刷一遍。

一面

笔试题

  • 给定一个表达式,如1*2+3/5+7,其中操作符只有加减乘除,没有括号,数字一定是非负数。要求编写一个程序输出表达式的结果。


  • 非常简单和基础的题目,涉及到逆波兰表达式。用一个符号栈和一个数字栈分别保存符号和数字,每当读到一个新的符号的时候,看看前面有没有优先级等于或高于该符号的运算符,有的话就立刻进行运算,这样可以保证运算顺序是正确的。最后把符号栈里剩余的符号依照出栈的顺序进行运算即可。
    另外这道题还有一个偷懒的方式,使用python的eval函数可以直接解析表达式并得出结果:

exp=input()
print(eval(exp))
  •    假设人群有1%罹患某种疾病,99%是健康的。某种检验手段,误检的概率是1%,就是说,健康的人有1%被误检为阳性,而患病的人有1%被误检为阴性。当某个人体检时被检出阳性,那么他已经得病的概率是多大?

  • 这是一道经典的先验概率和后验概率的题目,我们记  为一个人患病的概率,  为检查得出阳性的概率,则  代表一个患病的人被检查为阳性的概率,而我们要求的就是  。
    从题目中可以得出:

    由贝叶斯定理:

    可得:

  • 广州对外地车牌实行开四停四策略,你需要实现一个算法,根据以往若干天的行驶情况,判断它在哪几天违章。


  • 这个问题首先要求你要知道什么是开四停四策略。当时面试官和我讲这个我想了好久才明白什么是开四停四……


  • 开四停四是指你最长的连续开车间隔不能超过4天,如果你连续开了4天车必须休息4天再继续开。这里注意这个连续开车间隔是允许中间有一些天是没有开的。也就是说你开车的时间里最近的连续开车起点不能超过4天。那么如何判断开车起点再哪呢?我们可以看看开车的那一天的前面是不是已经有4天没开车了,如果是的话说明这个点可以作为起点。
    题目本身很简单,但理解这个规则还是需要逻辑清晰点的。

这三道题我当时都答出来了,但后面回想起来,当时的思路是有点混乱的,不是特别清晰,导致最后程序写的也不是很漂亮。所以特别赞同一句话:"Think twice, code once"

C++

  • struct和class的区别在哪?


  • 首先在C++里,struct和class都是类,但是如果不特殊声明,struct的成员均为public成员,class的成员均为private成员。继承也类似,struct默认是public继承,class默认是private的继承。C++之所以有struct这个关键字主要是出于向C兼容的考虑。在C语言里,struct只能定义成员变量却不能定义成员函数。

  • __func__和__LINE__的实现机制是怎么样的?
    __func__是C++11里的一个预定义变量,__LINE__是一个宏,__LINE__在预处理阶段展开,而__func__在编译期做完词法分析后获得AST后可以很轻易的展开(应该是在语义分析阶段)

  • 虚函数的实现原理?



  • 虚函数的实现和虚函数表(虚表)和虚函数表指针(虚指针)有关。每个定义了虚函数的类都会有个自己的虚表,负责存放对应虚函数的函数指针。而每个对象都有一个虚指针,指向对象所属类的虚表(如果是多继承的话会有多个虚指针,通过不同的名字区分)。这个虚指针在构造函数执行的时候被初始化:首先默认执行父类的构造函数,此时虚指针存放的是父类的虚表地址,再执行子类的构造函数,这样虚指针就被替换成子类的虚表地址。(进一步展开,这也是为什么构造函数不能是虚函数的原因,因为在执行构造函数前,虚指针还没有被初始化!)

计算机网络

  • 解释一下TCP的流量控制和拥塞控制有什么不同?具体机制是怎么样的?
    这个非常基础了,流量控制是用来防止接收方缓存不够的情况的,由接收窗口rwnd控制,如果发送方检测到rwnd=0,那么就会发送一个空数据包并停止继续发送数据而拥塞控制是用来防止由于网络拥堵导致丢包的情况,由拥塞窗口cwnd控制,拥塞控制有三个模式:慢启动,拥塞避免和快速恢复。(剩下还回答了好多细节,这里就不贴了)

  • 简述一下TCP的三次握手机制?
    emmm这个太简单了,不讲

  • 知道http和https吗?
    https指的是http+TLS/SSL,即在http之上加入了安全套接层(但从协议栈上看,TLS/SSL的上级协议是http协议)。由于http的所有内容在网络上以明文传输,可以被所有中间节点看到,所以有巨大的安全风险(特别是传输一些敏感信息的时候)。https则会把内容加密后再进行传输,中间节点无法得知真实内容,可以避免此类的安全问题。

  • https的加密机制了解吗?
    https的加密既使用了对称加密也使用了非对称加密。首先,服务器生成非对称加密算法所需的公钥和私钥,将公钥明文传给客户机,客户机在本机上生成对称加密所使用的通讯密钥,用公钥加密发送给服务器,由于公钥加密后的密文只能通过私钥解开,因此传输节点无法得知通讯密钥内容。这样后续交流双方只需要使用通讯密钥加密信息就可以实现安全通信了。


  • 但是如果传输过程中存在一个中间人,他把服务器的公钥换成自己的公钥传递给客户机,这样客户机发送通讯密钥的时候中间人就能通过自己的密钥解开,得到通讯密钥,再用服务器的公钥加密后传回给服务器。此时,中间人就在客户机和服务器没有察觉的情况下成功窃听到了信息。为了防止这样的情况发生,我们需要验证公钥是否真的来自于服务器。

  • 这时候我们想到可以找一个受信的第三方(也就是CA),把公钥,域名,第三方机构等信息放在一起做一次hash(做hash的目的是把这些信息变成定长的比特串,降低非对称加密所需的时间,因为如果内容很长的话加密时间也会很长),再用CA的私钥加密,得到一个对内容的签名,由于中间人无法得到CA的信任,因此即使中间人可以伪造证书,也无法伪造签名。


  • 现在,服务器直接发送证书和证书签名,当客户机收到证书和签名时,他首先找到是哪个CA发行了证书,再用CA的公钥解密签名,与客户机自己对证书生成的hash对比,如果一致就说明这个公钥是可行的,可以确定是服务器传过来的公钥了!(证书)

  • https的握手机制?

  1. 客户机发出hello连接请求,附上自己支持的安全协议的版本,能够使用的加密套件的列表等相关信息。

  2. 服务器回应hello请求,根据本机上能使用的加密套件,发送此次握手使用的协议版本,哪种加密套件以及自己的证书。

  3. 客户机收到信息后,验证证书真伪,如果通过验证就在本地生成通讯密钥,通过公钥加密发送给服务器

  4. 服务器收到信息后,通过私钥解密获得通讯密钥

  5. 后续通讯均通过通讯密钥加密进行

OS

  • 如果在C++中assert发现出错,linux会如何处理?


  • 如果assert的时候发现表达式为false,assert会打印错误信息,然后调用abort结束程序,不进行清理,后续的操作留给操作系统处理。此时linux会强制kill掉该程序,留下一个僵尸进程等待父进程或init来处理。僵尸进程我当时没答出来,后面问了同学才知道。

  • 进程和线程的区别?

  1. 进程是资源分配的最小单位,线程是CPU调度的最小单位

  2. 每个进程有自己的PCB,有单独的代码和地址空间。而一个进程下的线程共享代码和地址空间。

  3. 线程相比于进程,线程间切换的消耗更小。

  4. 相比于进程,线程如果崩溃对系统造成的

  • 讲一讲linux下进程间通信的几种方式?
    管道,命名管道,消息队列,共享内存,信号量,套接字,信号。

  • 了解epoll吗?
    这个当时没回答出来……这里补充一下我后面思考的答案,参考了这篇博文,讲的很好。


  • linux下有五种OS模型,分别是:阻塞型,非阻塞型,IO多路复用型,信号驱动型,异步IO型。大部分socket接口都是阻塞型的,但有一个巨大的缺点就是如果要读取的socket未就绪进程就会阻塞,这导致一个进程同时处理一个socket,如果同时有多个访问就要对每个访问单独开一个进程处理,这会占用大量的系统资源。而使用IO多路复用则是由一个进程同时监视多个socket,当这些socket中的一个准备就绪后进程对此进行处理,这样就节省了内存资源。IO多路复用比较适合于处理连接数较多,但活跃连接数较少的情况,比如提供web服务。在linux下常用的多路复用函数有select,poll和epoll。select和poll查询socket是否就绪使用的是轮询法,效率是,而epoll由内核直接支持,通过callback直接将对应的文件标识符加入就绪队列,从而达到的时间复杂度。epoll实际上是一组函数,包括epoll_create,epoll_ctl和epoll_wait。


  • 在触发方式上,epoll有ET(边缘触发)和LT(水平触发)两种模式,在ET模式下,仅当socket刚刚就绪时会触发epoll,epoll告诉我们该socket就绪。如果没有及时处理,epoll不会再次告知我们。

二面

二面发挥的不是特别好,和考官通话的时候通话质量特别差,听不清对方在讲什么,后面换了一个手机来打就好多了。这次考官考了好多底层的东西,我很多都答不上来……包括自己发现虽然用C++写了很多程序,但是对于底层的了解还是欠缺,考官的问题只能回答一点最基本的,一旦深入就无法回答了。当时面试结束抱怨了一下学校教的太浅,同样去tx面试的同学回了一句话:“等学校教你这些,不是在找死吗?”

C++

  • 指针和数组名有什么区别?

  1. 数组名被解释为其第一个元素的地址,而对数组名应用地址运算符(即&)时,得到的是整个数组的地址。

  2. 使用sizeof对数组名进行运算时,得到的是整个数组的长度,而对指针进行sizeof运算得到的是指针的长度。

  3. 当数组名作为参数传入函数时,数组名会退化成指针,参见下面这个示例:

void func(int arr[]){
 cout<
  • C++的内存布局是怎么样的,从低到高分别是哪些区域?
    C++的内存布局从低到高分别是代码区,全局变量区,堆,栈,文字常量区。堆的分配由低地址到高地址,栈的分配由高地址到低地址。

OS

  • linux下有哪些进程间通信的方法?哪一种最快?


  • 这个问题一面也问到了,这里不再重复。进程间通信最快的方法是共享内存法,因为并不需要拷贝,直接通过某些手段把同一段内存映射到两个进程的地址空间中。

  • linux中进程的内存布局是怎么样的?
    又是内存布局……我依然不会,只能随便扯了一点和虚拟内存相关的东西。这里附上一个知乎答案里的图来解释:

腾讯后台开发暑期实习 一面&二面总结(附答案)_第1张图片

  • 假设在linux下,有一个程序首先读入一个文件,修改了其中的内容,再写入原文件中,请你谈谈在这个过程中OS做了哪些工作。
    这个问题一下就问到很底层的知识了,只能很浅显的说了一些我会的,如果大家会这道题可以帮我补充一下。。

数据库

  • 了解mySQL中的存储引擎吗?
    这个以前上实验课的时候了解过,但是好久没看不记得了……mySQL的两个最主流的储存引擎是MyISAM 和 InnoDB,通常我们使用的是InnoDB。他们的差别:

  1. InnoDB支持事务,MyISAM不支持。

  2. InnoDB支持外键,MyISAM不支持。

  3. InnoDB是聚集索引,MyISAM是非聚集索引。

  4. InnoDB不保存表的具体行数,MyISAM保存了表的具体行数

  5. InnoDB最小的锁粒度是行锁,MyISAM是表锁。

通常来说,InnoDB适合增删改多,且需要事务支持的情况,而myismp支持高效率查找,适合读比较多的情况。
事实上,mySQL的储存引擎还有MEMORY,ARCHIVE等,他们各有各自的优缺点。但主流的还是上面提到的两个储存引擎。

  • 如何优化SQL的查询速度?
    这个不知道怎么回答……我说了可以建立索引,分页,缓存部分内容到内存(比如redis就是类似的原理)三个方法,也不知道对不对。

算法题

  • 给你一个100万*100万的图像,里面有一条像素点构成的首尾相接的曲线,这个曲线形成了一个闭合区域,现在给定你这些像素点的坐标,问你如何判断一个某个点在里面还是外面。


  • 这个问题可以转化成求一个点是否在一个多边形内部。我们首先可以进行一个简单测试,先取得这些像素点的最大和最小x,y坐标,构成一个恰好将闭合区域包裹在里面的四边形,看看这个点是否在该四边形里面,如果不在那么肯定不在多边形内部。接下来我们采用射线法:过给定点做一条与x轴平行的射线,这条射线会和多边形形成一系列交点,如果交点数量是奇数,那么就说明在多边形内部,否则就在外部。当然这样是没有考虑一些特殊情况的,更加详细的解答可以参考这个链接。

  • 有一颗二叉树,每个节点有一个唯一的值id,现在给定三个不同的id值a,b,c,问他们所属的节点的LCA是哪个节点?
    这个问题很简单,用tarjan跑一遍就出来了。不懂的同学可以学一下求LCA的tarjan算法。

总的来说,腾讯后台岗位对计算机操作系统的一些底层知识要求比较高,但算法要求比较低,问的都是比较简单的算法题。

你可能感兴趣的:(腾讯后台开发暑期实习 一面&二面总结(附答案))