4月份才开始真正的投简历、找实习,就有点晚了。有些公司的网申都快截止了才投。这个时候有点着急了,所以我是看到c++关键字就投了简历。
第一次投递,还没来的及看面经看看都有什么题目就受到了面试邀请。因为时间冲突我申请了延后一天,不知道为什么当天下午就直接来了电话面试。
虚函数
大概把虚函数表,有继承的情况,继承多个父类部分有虚函数的情况简单说了一下
STL
set和map底层实现
使用自平衡二叉树
确定是平衡二叉树吗
感觉是吧, 我没有太过仔细看里面的实现(实在是太紧张了, 脑子空白, 当时就凭着记忆回忆了数据结构学的所有的树, 回答了我觉得最合理的一棵树. 后面回想可能是面试官希望听到具体的红黑树而不是泛泛的平衡二叉树)
你是没有了解过STL的实现吗?(察觉到我没有准备或者很菜, 有点不开心了)
不好意思, 我平时这边可能欠缺注意.
那要是你实现一个链表你会怎么实现?
用双向链表吧, 牺牲一点空间换一点性能吧
看过的书
没仔细看过c++的技术书,看的一般是应用类的。
确实是我自己的问题, 我没有做好准备就开始浪费他们的时间. 痛定思痛, 专心准备几天
初生牛犊不怕虎, 投了一个不知道的岗位. 因为其他位置要求了一些很具体的要求, 我没有达到. 只剩下这个相对吻合.
一开始简单讲了一下项目,觉得没有特别之处,就开始问基础知识了
被转岗,简历没通过。面试过程很轻松和舒适,我都不知道是怎么挂的。
一家做存储的公司,但是我看要求上没有太多,所以我去试试了。
面试官个人情绪很重。
这次面试直接自闭,感觉就很废物。啥都不会,但是也托这次面试的福,我再后面两天刷了一下raft一致性的初始论文、MapReduce、GFS的论文,发现其实这种paper其实也就是一种正式的博客。只不过很权威性。而且这些技术博客的语言已经很简单了,就是思想比较难而已。
这次面试很痛苦,但是收获也多。
简单聊项目,聊了聊面试过程中遇到的难处。和重新设计会怎么操作。
还有一些比较基础给忘记了
先聊了一些校园经历
int (*a[8])(int)
是什么
函数指针数组,参数int、返回int、这个系列有八个函数可以用偏移或者[]访问到。
给了一个更复杂的式子,其实也是一个函数只不过已知其地址位0x1000000。要求是如何跳转到这个地址上。 首先想到的是CSAPP里面的缓存区溢出攻击。被反驳,
因为段错误。后面才想到其实可以定义一个二维指针,指向的地址是0x1000000
。然后用这个指针就可以使用这个函数了。
考了两个智力题,在面试官引导下做完了。
被鸽了30分钟,然后对方在家里面试我。
最后我问了面试表现,面试官说你这个第一天确实很失望,但还好第二题做回来了。
我以为挂了,因为简单题没搞出来。但是没想到一天后收到了offer,都没有什么HR面。深信服反馈也挺快的。
其实仔细想想,其实在一二面确定了基本功。在三面想了解我的拓展性,但是这轮面试我没把握好,浪费了。
第一次被三个人同时面试,被吓到了以为是直接准备三面结束呢。
真的很详细。我每说一个点基本都会被仔细的问一下。
比如我提到解数独算法,在普通的书的遍历基础上加入随机性提高效率。
对面一下子来兴趣了。
项目设计的算法
你这个算法是有数学证明吗
不是数学整明,而是在解的分布上,大致遵循正态分布在整个解空间中,所以我建立的随机算法也是准寻一个正态分布。所以我们就是这样做的。
那为啥不直接从中间找
直接从中间找其实有点类似与深度学习过程中的过拟合,把正态分布过拟合成了中间为100%概率。这样虽然在这个区间内有良好的性能,但是对于最差情况就很糟糕了。加入随机性就是希望降低最差情况的影响。在最后的40G数据量测试下都能保证较好的性能
编译器
你说的这个编译器里面的闭包特性是你预计要实现的是吗
用我对维基百科的了解讲了一下闭包的概念。实现思路就是一个匿名函数,然后把定义这个匿名函数的函数的局部变量设置为调用处的内部匿名变量。使得在被调用的词法作用域内值被记录达到一种保存状态的效果。
这里问的频繁就没记住
问了几个子集树算法的问题,要我分别用BFS和DFS给出解。比较不同
这次总体体验很好,感觉把我的一些项目的细节都扣的很细节。
时间稍微有点远,忘记细节了。
IO模型
b+树,红黑树的特点
红黑树是自平衡树,平衡依据是:黑色平衡,不同于AVL树的深度平衡。黑色平衡对插入节点和删除节点时触发平衡操作的概率降低,所以这两种操作性能好性能,但是正是因此查找性能差。因为深度不平衡
B+树是B树的一种,B树类是m叉树,所以高度比红黑树低,索引次数少。B+树在B树的基础上更改设定为只有叶子节点有值,并且叶子节点之间呈现一种链表状,因此对于范围查找性能好。同时对于数值的空间局部性更好,因此更好的利用了磁盘预读的功能。有利于连续的数据的IO。
两者区别:
B+树优点
红黑树优点
手机或者端设备再一次页面访问的时候会进行怎样的操作:
线程数的确定依据
优先考虑操作系统能分配的线程数,因为过多线程切换回来的负面影响
然后考虑线程的任务类型:
页、分段的问题
进程、线程、协程
线程之间的资源利用的权限,一个线程是否可以访问另一个线程的内容
对同一个IP的在一段时间内访问一定次数限制。
思路:
用一个map,最好是hash map对时间性能好,如果任务场景的存储空间有限则也可以使用红黑树这种map(其实主要是c++11 STL组件的新加的hash map我忘记怎么写了,牛客没有提示,不敢写怕尴尬)
然后每次来一个IP查询一次map,
如果没有则加入,并且写入IP的上次访问时间,访问次数置位为1
若有,
当前时间戳与保存的时间戳比较,如果在限制的时间内则,累加访问次数。不改变时间
如果超过了限制的最短时间,则刷新时间戳,并置位访问次数为1
这个题就是用std::map<IP,std::pair<Time,uint_8>>
。即可其中IP
和Time
是我自己定义的数据类型,因为面试官让我自己设计。uint_8
就是为了省空间。编写代码的时候两个尴尬的事情,我忘记了std::pair
库是哪个头文件的,编译出bug,还有就是不知道为什么中间输入法变为中文,有一个地方的,
变为中文的,
但是在牛客上的提示却很奇怪。让我和面试官找了一会。后面样例全过了。
一面二面是连着来的,二面没怎么问基础知识,主要是聊了项目经历。
LRU算法,leetcode 原题。我说了用次数因为考虑频度,因为直译是最少最近使用,但面试官非要让我用时间,怀疑我没理解LRU。没有办法,其实我估计面试官也是在leetcode上看到的这个题,因为leetcode官方给的答案也不是LRU的真正含义,而是类似于最近没被使用(最远被使用的踢出cache)但是面试官怎么要求怎么来。
思路(面试官没有给要求,完全自由度)
get
、put
、find_lr_node
操作。主要维护一个map<node,Time>
find_lr_node
踢出,再插入find_lr_node
的算法就是找到最小Time,是一个排序时间复杂度(nlogn)pair<Time,node>
优先级用Time作为标准。每次使用堆删除节点重新插入。O(1)时间复杂度最大岛屿面积。一个二维空间中,1表示岛屿,0表示海洋,上下左右四个方向相连的区域认为是一个岛屿。
思路(简单题,暴力搜索)
定义BFS算法,因为上下左右都有用广度优先更符合直觉,
如果当前节点为1,设置当前值为1,并把当前节点清零表示访问过了
反之,返回零
遍历岛屿
常用命令
查看内存命令
不会,因为我是用的是wsl的Linux,查看的时候都是之间看windows的任务管理器。Linux平常就写代码和编译
HTTP报文格式和内容
判断一个报文如何读完了
常用数据结构,及其应用场景
线性表
树
图
还没讲完被打断了
分布式协议
我就讲述了我实现版本的2pc(和一开始提出的不同,因为有恢复追踪)
平时咋学习的
遇到陌生学课一般先看一下历史脉络,看一下一开始提出了什么,为了什么缺陷又提出了什么,解决什么功能。看一下有没有专门的引导或者书籍或者paper。
如编译,
对一个无序数组中给出最大的组合(最后都没编译出来,面试官也不熟悉c++,有一些库函数忘记是哪个库了,所以我自己写了find函数啥的)
思路:
利用排序,只需要写比较函数即可
比较函数原则:
当前位比较,不同则返回比较结果
相同则比较下一位
这个思路最后给面试官讲出来了,后来我发现可能在一部分case下出错。判断函数可以很简单:
xxxxxxxxxx
31bool cmp(string a, string b) {
2 return a+b > b+a;
3}
整明用反证法。主要思想就是两个数拼起来能让整体大的在前。
你平时在学校刷过题吗?
老老实实回答,没有。就写过20多道mid题目,剑指offer看了10几道。