记2024春招,本大三菜狗参加了小厂和大厂面试,实时更新大厂面试被拷打的真实记录,包括一面二面笔试(有机会过一面的话),总结经验。
自我介绍:
Q:介绍一下你自己
A:简要说了大一到大三学了什么语言课程,做了某后端项目负责什么(面试官:细讲一下项目)
于是讲了项目用到的技术、框架等:golang,gin、gorm,mysql,zerotier,gstreamer,......。
项目经历及相关知识拷打:
Q:讲一下在项目里做了什么,用了什么技术?
A:略,简要讲了golang以及用的框架还有其他的视频、网络、服务器相关技术。
...........我是菜鸡,接下来没想到从数据库开始挖,面试前重点全放在网络、go、和刷题了,数据库这块问答基本废)
Q:数据库分页分表怎么做的?
A:项目数据比较少,基本用脚本填充,暂时没接触到分页(我也不懂,直接实话实说了)
垂直、水平分表,顺便讲讲优缺点。
Q:数据库用的什么引擎?
A:我逆天,忘名字了,我说不知道。
innodb,顺便讲讲优缺点和特点
Q:这里说到了索引,简要讲一下。
A:我们将原来的手机号等改为用自增id做主键,并将自增id作为索引与其链接,加快查询速度。
索引,讲一下结构(B+树,hash),特点分类
Q:好那么索引是用什么数据结构存储的?(mysql这块数据结构我确实基本没看,疏忽,基础知识储备也不够,需要加强,备试的时候一直把数据库这块地位放轻了)
A:不知道,我只知道增删记录需要更新索引结构,索引过多也会影响效率。
B+树
................接着开始问go、gin这块
Q:实现的是什么网络库?
A:我看gin实现的json和http库我就说http了。
Q:知道gin的瓶颈在什么地方吗?
A:不知道,只了解过底层结构,没研究过优化和瓶颈。
Q:gin为什么能实现高性能(底层结构)?
A:这块还好了解过。我答了三点,1.gin对配置了路由的路径采用树结构存储(类似按"/"划分不同深度存储),加快查询效率。2.gin处理请求是使用的goroutine,每个请求的处理都跑在goroutine,实现异步。3.中间件的链式顺序采用的切片结构,由于其动态改变容量便于增删的特性。
Q:redis在分布式中的角色?
A:对分布式不太了解。
Q:对c熟悉吗?
A:一般,学系统编程写过线程进程文件相关的。
Q:epoll和select的区别?
A:不知道,只知道都是处理多路监听。(乱答)
select O(n)只能捕获到有IO事件流,不知道具体是哪一个,需要进行无差别轮询,发现IO就绪进行相应的IO操作。
epoll O(1) 是事件绑定fd类型,捕获时直接知道哪个流发生哪个IO事件,区别于无差别轮询和忙轮询。
..........回到项目
Q:有对gin进行过压测吗?
A:没有。(甚至没操作过压测,简历上写的优化后系统能够处理每秒超过 500 个请求,结果答不上来压测,事实证明一定要准备齐全,起码要实际操作过,知道性能瓶颈能达到多少。)
ab工具
Q:讲一下项目中碰到的技术难点?
A:我加上这次面试,两次面试都答偏了,全说成了学习技术上比较困难的技术.....
正确来说应该回答技术实操过程碰到的卡壳问题,比如小程序由于http无状态,鉴权需要携带参数来鉴权、比如网络、配置等影响导致某参数的获取困难,或者压测过程性能瓶颈选择了升级服务器、升级数据库等,重点要讲发现问题后一步步探讨问题所在并想办法解决的过程。反思!
算法题部分:
1.字符串单词逆序,“i am a pig”----->“pig a am i”,面试官:很简单的题。
A1:一开始紧张看快了,看成整个字符串逆序,夸夸几下写了前后指针,然后不断调换直到l==r。结果面试官提醒是单词逆序。
A2:看清题目,用的双指针,最丑陋的方法,一个一个单词找。复杂度O(n)。
Q:面试官:有没有复杂度更低(应该是空间,后来发现各种方法最低时间都是O(n))的方法?
A3:实在想不出来了。。
补充答案:原题见leetcode:单词逆序(简单)
https://leetcode.cn/problems/fan-zhuan-dan-ci-shun-xu-lcof/description/
class Solution {
public:
string reverseMessage(string s) {
//1.双指针丑陋找单词 O(n),O(n)
int len=s.size(),l=len-1,r=len-1;
string ans="";
//从后往前,找到单词末尾字符
while(r>=0&&s[r]==' ') r--;
l=r;
while(r>=0){
//找到该单词前的一个空格
while(r>=0&&s[r]!=' ') r--;
ans+=s.substr(r+1,l-r);ans+=" ";//把r=-1的情况也包含了,这里不用if(r>=0)
while(r>=0&&s[r]==' ') r--;
l=r;
}
ans=ans.substr(0,ans.size()-1);
return ans;
//2.用stringstream简洁 不过也是O(n),O(n)
//string ans="",temp;
//istringstream ss(s);
//while(ss>>temp) ans=temp+" "+ans;
//ans=ans.substr(0,ans.size()-1);
//return ans;
}
};
2.有一百亿个数,找出其中出现次数为偶数的数,可能有多个。
A1:最先想到的肯定是哈希了,空间、时间都O(n)。
Q:面试官:空间复杂度有没有低一点的。
A2:连续异或。
Q:面试官:提示,4bit,一百亿个数,结果够存吗?这里我一开始还没明白意思。
面试官提示,那假设是【0,1】范围内的一百亿个数呢?
A3:我想半天没get到点,最后说那回去思考思考。
面试官提示的方法是!!!:对于可能出现的一个数字,用2bit记录,其中一个bit记录是否出现过,初始0出现1(否则没法区分不存在/出现次数为偶数);另一个bit,这个数字每遍历到一次则改变一次(0变1,1变0),初始0,最终0则说明出现次数为偶数,最终1则说明出现次数为奇数。
然后发现leetcode原来做过一道类似的:寻找重复数,是【1,n】范围内的1+n个数,非常相似,并且也是要求空间O(1)。
补充答案:原相似题可见leetcode:寻找重复数(中等),原题是【1,n】范围的n+1个数,要求不改变原数组,且空间复杂度O(1)。https://leetcode.cn/problems/find-the-duplicate-number/description/。
//1.(这里暂且假设一百亿个数能用数组存,实际当然不行)。重点是空间O(1)的两个算法思路
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int n=nums.size();
//1.对号入座法,各回各家 修改了原数组O(n),O(1)
// for(int i=0;i<n;i++){
// if(i==nums[i]) continue;
// if(nums[nums[i]]==nums[i]) return nums[i];//家被一样的人住了
// swap(nums[i],nums[nums[i]]);//把数nums[i]放到索引也为nums[i]的位置(回家)
// i--;
// //注意!交换之后缓过来的那个数还没遍历过,不能直接i--跳过了,要i--回退一次,把这个数遍历一下
// }
// return -1;
//2.环形链表法 不修改原数组 O(n),O(1)
//类似环形链表Ⅱ,只不过在数组中借助值-下标模拟链表跳跃 O(n),O(1)
int slow=nums[0],fast=nums[0];
while(true){//由于必定有环,所以这里不用像环形链表Ⅱ一样加什么边界判定了
slow=nums[slow];
fast=nums[nums[fast]];
if(slow==fast) break;
}//第一次相遇
fast=nums[0];
while(slow!=fast){
slow=nums[slow];
fast=nums[fast];
}//第二次相遇
//详细原理见环形链表Ⅱ
return slow;
}
};
//2.直接快排O(nlogn),再遍历找nums[i]==nums[i+1]的重复数,空间原地
//3.想起面试前刷到一篇面试实录文章,问题基本一样:现在有一百亿个qq号,如何去重?那篇文章里回答的是“布隆过滤器”?等我了解一下是什么结构。
之后想起面试前刷到一篇面试实录文章,问题基本一样:现在有一百亿个qq号,如何去重?那篇文章里回答的是“布隆过滤器”:布隆过滤器相关文章链接如下,讲的易于理解,结构类似二进制位数组,将元素哈希后的多个值取余数组len,然后映射到相应数组下标位置存储,用于判断元素是否已经存在,可能误判:判断没有一定没有,判断有可能是其他元素的哈希冲突导致的。难道面试官想问的是这个?
http://【布隆(Bloom Filter)过滤器——全面讲解,建议收藏 - 优快云 App】http://t.csdnimg.cn/k1n6P
收尾:
Q:实习时间?
A:3月开始就可以,上学期课选的多这学期基本课少,时长3~6个月都可以。
总结:
1.基础知识不扎实,主要体现在数据库这块。网络这块复习了很久面试没问到,但如果面试官想问深估计也站不住,毕竟网络就复习了基本的tcp、udp、路由、握手挥手、以及从url到服务器代码的过程这些。
2.了解框架底层除了了解数据结构,优点及其和结构、调度等相关的原因,还需要了解其缺点、瓶颈及发展方向,以及导致这些问题的数据结构上的原因或库的限制等。
2.项目复盘不够,还是得复盘项目过程遇到的问题,我主要讲的是学习技术的困难以及遇到问题经过商议选择了什么技术,是有点偏的。实操方面难点应该更是需要回答的,比如性能测试出来的瓶颈怎么解决的,这块还需要去做一下压测,以及网络相关的获取某些参数的影响等。
3.算法题多做链表、数组类,因为这是面试短时间最容易出题的(字数少好描述,考察方式多),也是最能考察相关二分/双指针/灵活技巧等方法的题目类型,因此多做数组链表题目并且不管中等/容易都要想时间/空间最优解,面试官就喜欢从这些简单数组链表题的最优复杂度切入考察!
尽量多想想最优解,时间最优,空间最优。而且需要对类似2题这样的,面试官喜欢问的大规模数组类的题目多接触多思考,比如一百亿个数,找最大最小找重复找奇偶正负这些,空间复杂度以及时间复杂度的最优。