字节跳动游戏客户端开发面经

字节跳动游戏客户端开发面经

  最近好久没有更新文章了,因为在准备实习,我研究生是用深度学习搞医学图像处理的,同时也是因为女生的缘故,搞算法其实不太占优势,(主要是我没怎么好好学习机器学习,这门课就是搞算法的核心基础知识)所以想着去开发岗,例如前端或者后端,客户端什么的,但是我又对这些东西不太了解,充其量就本科学了一下,并且我也没有任何相关的项目,全都是做的研究。但是,我怎么会认输呢,于是我复习了20多天最终字节跳动过了三面技术面,所以想将自己的心得体会写一写,这篇文章重点是对于那些不太有项目或者说简历也没有特别出彩的地方,没有与投的岗位相关的工作的小伙伴,后续我可以向我朋友要一些算法岗的心得。

前期准备

  大体说一下我的准备方式吧,其实寒假过完3月初我才知道要开始实习了,然后闲聊群里面都在发各大厂的实习招聘信息,也看到很多人都开始投简历了,于是我立马开始准备一些十分重要的基础知识:
   ∙ \bullet 首先面试这种开发端客户端什么的最重要的就是掌握基础知识【在你没有任何可以凸显的东西上】,当时面试官跟我说的就是招实习生也不是让你一定有什么项目,一般而言都是看你基础知识掌握的如何,学习能力是否比较强,算法能力是否足够,他们可以通过这些方面来判断你是否有潜力。就比如说操作系统,数据结构,计算机网络,操作系统,必问经典基础科目,当然有的面试官还会问你计算机组成原理,最好都看一遍,我是跟着一个博客看的,对我真的大有裨益,先贴一下参考网址【计算机网络操作系统数据库】,基本都涵盖了各类知识了。除此之外,还有一个知乎公众号路人甲计算机网络操作系统数据库】也有这些基础知识,小伙伴们可以一起看。简单来说,计算机网络很喜欢问TCP和UDP,三次握手四次挥手,操作系统线程进程区别,进程间通信方式等,数据库很喜欢问索引,引申到为什么用B树B+树,而不用哈希表等,最重要的就是你需要让面试官跟着你的思路走,这样面试官会对你的整体水平有更加深刻的了解,后续会提到。
   ∙ \bullet 其次需要去看一下数据结构和C++,因为面试官很喜欢问你最熟悉的语言是什么,我的是C++,当然看你自身熟悉哪门语言,然后面试官就会十分详细的往下问【C++常见知识汇总】,数据结构和算法又是计算机专业的核心基础知识,所以必问。可以去知乎上面搜一下关于数据结构的知识点,有比较厉害的公众号比如:程序员景禹数据结构到底难在哪里】、程序员吴师兄怎么学好数据结构】,都对我很有帮助,把较难的知识点都用动画的形式浅显的表示出来。然后能够用自己的方法解释出来就可以,面试官看的是你的思路,不需要太详细。还有就是博客【数据结构算法常见面试考题
   ∙ \bullet 最重要的其实就是算法题目了,面试的时候一般会在一个小时左右,半个小时会问你一些基础知识,但是远远不及算法题目你做出来让面试官欣赏你,因为基础知识都是背的或者理解的,可能稍微短期准备一下能应付过去,但是算法题真的是靠长时间的积累,我同学说要是面试不太好但是算法题代码写得快照样能过,面试官很喜欢出动态规划和二叉树的题目,这个时候就不能乱刷题目了,需要按部就班的有条理性的去做题,我是跟着一个微信公众号代码随想录刷题最强指南 】刷了一下题目,这个文章写的真的很不错,因为我字节三面就碰上上面讲解的树的原题了,所以很快就回答出来了,并且里面有对哈希表的专业讲解,红黑树,map,set深层解析,面试的时候就可以给面试官讲解一下。

面试经过

  简单说一下面试的具体方式,就是你能看到面试官,面试官也能看到你,然后面试官的窗口在最右边,中间则是一个写代码的平台,跟leecode很像,然后也有简单函数的自动提示,左边则是出题的地方,题目会显示在上面,而且也不一定需要运行,你只需要输入几个简单的测试样例给面试官看,他改一下能通过就算过了,当然有的面试官就让你直接运行,过了就过了,其实面试官一眼就能看出来你的代码是否是对的,当然如果运行不出来也没关系,可以直接在上面用cout进行调试,就很方便,最终如果思路是对的,其实没运行对也没关系,面试官也不会卡你,但是核心的思路一定要写出来或者跟面试官详细说一下思路。

一面

  一面比较简单,听我同学说,一面是同事,二面是其他部门交换着面试,三面就是你的leader给你面试,所以一面其实不需要太紧张,一般每一次面试都会让你做一个自我介绍,随便介绍啥都行,一般在5分钟,接下来25分钟就是问题(声明一下,答案都是我从各个博客汇总来的,仅供自学和参考,谢谢!):

  1、描述一下TCP和UDP的区别?

  TCP和UDP协议是OSI模型传输层协议,TCP提供可靠地通信传输,而UDP则常被用于让广播和细节控制交给应用的通信传输。它们之间的区别包括:
   ∙ \bullet TCP是面向连接的,UDP是无连接的,也就是说发送数据前不需要建立连接;

   ∙ \bullet TCP是可靠的,UDP是不可靠的;

   ∙ \bullet TCP只支持点对点通信,广播和多播不适用于TCP,UDP支持一对一、一对多、多对一、多对多的通信模式;

   ∙ \bullet TCP是面向字节流的,UDP是面向报文的;

   ∙ \bullet TCP有拥塞控制机制;UDP没有拥塞控制,适合媒体通信;

   ∙ \bullet TCP首部开销(20个字节)比UDP的首部开销(8个字节)要大;

   ∙ \bullet TCP数据传输慢,UDP数据传输快。

  这个时候,你可以询问一下面试官是否可以拓展,若不可以,继续下一个问题,若可以,这时候就需要发挥你对TCP和UDP的真正了解了,相关的拓展问题如下:

  拓展问题1:TCP的拥塞控制与流量控制

  流量控制:TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。TCP使用的流量控制协议是可变大小的滑动窗口协议。

  拥塞控制:计算机网络中的带宽、交换结点中的缓存及处理机等都是网络的资源。在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就会变坏,这种情况就叫做拥塞。拥塞控制就是 防止过多的数据注入网络中,这样可以使网络中的路由器或链路不致过载。然后后面就解释一下慢启动,拥塞避免,快重传,快速恢复就好啦!
  具体内容可以参考TCP窗口滑动与拥塞控制

  拓展问题2:TCP和UDP应用场景

  TCP:当对网络通讯质量有要求的时候,比如:整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。在日常生活中,常见使用TCP协议的应用如:浏览器,用的HTTP;QQ文件传输。

  UDP:当强调传输性能而不是传输的完整性时, 要求网络通讯速度能尽量的快。如:QQ语音 QQ视频等,这时候其实也可以说,自己和面试官的面试通话就是一种UDP的应用场景。

  拓展问题3:TCP的三次握手和四次挥手

  这个问题我被字节问了也被腾讯问了,说明此题目的重要性,可以完全按照自己的理解去说明一下,参考【计算机网络】。

  2、使用过的C++里面的标准模板库有哪些?

  实际上有vector,list,stack,queue,map,set.这个时候面试官会考察你vector底层实现原理,其实vector(向量)底层是一个数组,准确的说,向量是一个能够存放任意类型的动态数组【vector容器实现原理】,当容量扩充会扩充double。

  然后可以讨论到map和set,其实就是哈希表和红黑树了,这时候可以详细介绍一下【关于哈希表,你需要了解这些】可以拓展一下,比如数据库索引中的B树,B+树(可以详细介绍一下,并且说明两个树之间的区别【B树和B+树区别】)因为都跟红黑树相关。当说到时间复杂度时,此时面试官会问,既然哈希表查找删除效率为O(1),那为什么数据库当中不用哈希表而是用B+树来存储数据呢?【采用B+树的意义】,这样将数据结构和数据库串在一起,就可以融会贯通了。

  3、C++中的虚函数

  一面面试官只问了我虚函数是啥,但是三面的时候面试官会问的特别详细,虚函数里面具体的实现方法,这个时候就需要说到虚函数指针与虚函数表。请参考【虚函数详解】,按照我的理解通俗的来说,基类和派生类都有相同名称的函数,如果没有virtual的话,主函数中调用此函数时其实就是调用的基类的函数,若采用了virtual则调用的是派生类的函数,实现了C++中的多态性。

  4、C++中的static关键字的意义是什么?

  血泪史证明,这个问题简直就是无敌的存在,我一面刚问完我,我不会,紧接着第二面开头就是这个问题,然后在三面之前我详细了解了一下这个关键字并且在三面的时候进行了详细的介绍最终获得了面试官的好感。参考【C/C++中关键字static】和【C/C++ 中 static 的用法全局变量与局部变量】,只要认真看,一定能看懂的!而且很长能够你介绍10分钟了。

  接下来是一个编程题目,求链表中是否有环,考题不难但是需要考虑边界情况,同时你可以跟面试官拓展一下,例如如何知道环的长度,如何找出环的连接点在哪里,带环链表的长度是多少?【判断是否有环

二面

  字节跳动有时候可能会连着让你面试两场,第一面结束以后面试官会跟你说等15分钟下一个面试官来继续面你,这时候最好就是看一看上个面试官出的题目你不会的,然后抓紧背诵一下,不然像我一样第二个面试官第一个问题就是static关键字我还没看就十分尴尬了…

  1、C++中的static和const的用法?

  参考答案

  (1) static

   ∙ \bullet 修饰全局变量:存储在静态存储区;未经初始化的全局静态变量自动初始化为 0;作用域为整个文件之内。
   ∙ \bullet 修饰局部变量:存储在静态存储;未经初始化的局部静态变量会被初始化为0;作用域为局部作用域,但离开作用域不被销毁。
   ∙ \bullet 修饰静态函数:静态函数只能在声明的文件中可见,不能被其他文件引用
   ∙ \bullet 修饰类的静态成员:在类中,静态成员可以实现多个对象之间的数据共享,静态成员是类的所有对象中共享的成员,而不属于某一个对象;类中的静态成员必须进行显示的初始化
   ∙ \bullet 修饰类的静态函数:静态函数同类的静态成员变量一个用法,都是属于一个类的方法。而且静态函数中只可以使用类的静态变量。

  (2) const

   ∙ \bullet 修成类成员:在C++中,const成员变量也不能在类定义处初始化,只能通过构造函数初始化列表进行,并且必须有构造函数; const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。

   ∙ \bullet 修饰类函数:该函数中所有变量均不可改变。

  2、析构函数的作用?

  请参考【析构函数】,然后三面面试官问我构造函数为什么不能是虚函数…答案如下:
  从C++之父Bjarne的回答我们应该知道C++为什么不支持构造函数是虚函数了,简单讲就是没有意义。虚函数的作用在于通过子类的指针或引用来调用父类的那个成员函数。而构造函数是在创建对象时自己主动调用的,不可能通过子类的指针或者引用去调用。
  虚函数相应一个指向vtable虚函数表的指针,但是这个指向vtable的指针事实上是存储在对象的内存空间的。假设构造函数是虚的,就须要通过 vtable来调用,但是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。还有相似的问题:构造函数和析构函数可不可以有虚函数?析构函数一般写成虚函数的原因?都可以看一看。

  3、new和malloc的区别?new/delete malloc/free

  参考答案

  (1) 属性上:new / delete 是c++关键字,需要编译器支持。 malloc/free是库函数,需要c的头文件支持。
  (2) 参数:使用new操作符申请内存分配时无须制定内存块的大小,编译器会根据类型信息自行计算。而mallco则需要显式地指出所需内存的尺寸。
  (3) 返回类型:new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,故new是符合类型安全性的操作符。而malloc内存成功分配返回的是void *,需要通过类型转换将其转换为我们需要的类型。
  (4) 分配失败时:new内存分配失败时抛出bad_alloc异常;malloc分配内存失败时返回 NULL。
  (5) 自定义类型:new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。 malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。
  (6) 重载:C++允许重载 new/delete 操作符。而malloc为库函数不允许重载。
  (7) 内存区域:new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。其中自由存储区为:C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。自由存储区不等于堆,如上所述,布局new就可以不位于堆中。

  4、链表和树的区别,什么时候用树,什么时候用链表?

  树是数据结构的一种逻辑结构形式,一个前驱,多个后继,链表是数据结构的一种存储结构形式,用数据域以外的附加存储空间表明逻辑关系,树存储起来,可以用链式存储实现,一般而言,如果不需要删除增加这种方式的话用链表更好,面试官举的例子就是食堂打饭,单纯只需要排队打饭就使用链表。

  5.数据结构中图的存储方式

  邻接矩阵表示法 与邻接表【图的存储方式

  6.堆排序原理介绍一下

  堆排序

  然后是动态规划算法题目,问的其实就是查找字符串中最大回文字符串的长度,可以暴力求解也可以用动态规划【参考答案】.

三面

  u1s1三面确实那个面试官看起来对底层的东西十分了解,真的是信手拈来,首先还是自我介绍,然后直接问我你最熟悉的语言是什么,我说C++,然后就开始各种C++里面的知识问我,就前面提起的析构函数和构造函数等还具体问我虚函数的实现原理,实在是答不上来…

  1.define和template的区别

  【参考答案】,反正我没回答出来

  2.线程和进程的区别?

   ∙ \bullet 进程是对运行时程序的封装,是系统进行资源调度和分配的的基本单位,实现了操作系统的并发;

   ∙ \bullet 线程是进程的子任务,是CPU调度和分派的基本单位,用于保证程序的 实时性,实现进程内部的并发;

   ∙ \bullet 一个程序至少有一个进程,一个进程至少有一个线程,线程依赖于进程而存在;

   ∙ \bullet 进程在执行过程中拥有独立的内存单元,而多个线程共享进程的内存。

  3.并行和并发的区别?

  参考答案

   ∙ \bullet 并发是指一个处理器同时处理多个任务。
   ∙ \bullet 并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。并行指在同一时刻,有多条指令在多个处理器上同时执行
   ∙ \bullet 并发是逻辑上的同时发生(simultaneous),而并行是物理上的同时发生。

  3.进程有哪几种通信方式?

  参考答案

   ∙ \bullet 管道(pipe)及命名管道(named pipe):管道可用于具有亲缘关系的父子进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;

   ∙ \bullet 信号(signal):信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;

   ∙ \bullet 消息队列:消息队列是消息的链接表,它克服了上两种通信方式中信号量有限的缺点,具有写权限得进程可以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息;

   ∙ \bullet 共享内存:可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等;

   ∙ \bullet 信号量:主要作为进程之间及同一种进程的不同线程之间得同步和互斥手段;

   ∙ \bullet 套接字:这是一种更为一般得进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛。

  4.OSI模型七层介绍一下?

  参考答案

  1). 物理层

  参考模型的最低层,也是OSI模型的第一层,实现了相邻计算机节点之间比特流的透明传送,并尽可能地屏蔽掉具体传输介质和物理设备的差异,使其上层(数据链路层)不必关心网络的具体传输介质。

  2). 数据链路层(data link layer)

  接收来自物理层的位流形式的数据,并封装成帧,传送到上一层;同样,也将来自上层的数据帧,拆装为位流形式的数据转发到物理层。这一层在物理层提供的比特流的基础上,通过差错控制、流量控制方法,使有差错的物理线路变为无差错的数据链路,即提供可靠的通过物理介质传输数据的方法。主要是实现两节点间可靠地数据传输。

  3). 网络层

  将网络地址翻译成对应的物理地址,并通过路由选择算法为分组通过通信子网选择最适当的路径。实现两端点间的最佳路由传输数据。

  4). 传输层(transport layer)

  在源端与目的端之间提供可靠的透明数据传输,使上层服务用户不必关系通信子网的实现细节。在协议栈中,传输层位于网络层之上,传输层协议为不同主机上运行的进程提供逻辑通信,而网络层协议为不同主机提供逻辑通信,如下图所示。

  5). 会话层(Session Layer)

  会话层是OSI模型的第五层,是用户应用程序和网络之间的接口,负责在网络中的两节点之间建立、维持和终止通信

  6). 表示层(Presentation Layer):数据的编码,压缩和解压缩,数据的加密和解密

  表示层是OSI模型的第六层,它对来自应用层的命令和数据进行解释,以确保一个系统的应用层所发送的信息可以被另一个系统的应用层读取。

  7). 应用层(Application layer):为用户的应用进程提供网络通信服务

  5.声明和定义的区别?

  参考答案

  6.malloc会后面跟一个sizeof分配内存大小,为什么free的时候不会跟任何东西就直接可以释放内存了?

  参考答案

  7. C++中重载与重写的区别?

   ∙ \bullet 重载:是指同一可访问区内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型。

   ∙ \bullet 重写:指派生类中存在重新定义的函数。其函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致。只有函数体不同(花括号内),派生类调用时会调用派生类的重写函数,不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰。

  8. extern的用法?

  参考答案

  当然那个面试官还想问我关于unity的知识,什么粒子碰撞,但是我没怎么接触过,不太了解就实话实说了,然后就没了。

  9. 操作系统当中进程采用信号量互斥的问题有哪些?

  我记得就是PV原语,消费者和生产者问题等。参考答案

  然后就是算法题目,给你一个二叉树,请你返回其按 层序遍历 得到的节点值。(即逐层地,从左到右访问所有节点),与【二叉树,层序遍历登场】完全一致,只要看懂了基本几分钟就能写出答案来了!

  希望大家也能去自己想去的公司实习!加油!

猜你喜欢

转载自blog.csdn.net/weixin_43436958/article/details/115259611