字节跳动(头条)【校招,后端实习生一面已过】面试经验
小白第一次面试,非计算机专业,有点紧张,而且很多问题答得不是很好
1. 学习方式
问:听到你的自我介绍,应该关于计算机的知识都是自学的,那你能介绍一下你的学习方式吗?
答:(正常交流,无关紧要)
1. 自我介绍
正常流程,介绍自己的学习经历,在校情况等。
2. 缓存机制+数据结构
问:看到你的简历上面写了用过varnish做缓存构建CDN,能介绍一下他的实现原理吗?
答:varnish提供了两种缓存机制,既可以将缓存放入文件中,也可以在内存中进行缓存。如果接收到了客户端请求,会根据请求去检查本地是否有对应缓存,如果有就返回给客户端,如果没有,就转发请求给后端服务,并对响应的静态资源进行缓存。
问:如果让你去实现varnish,你会考虑哪种数据结构?
答:因为是缓存,所以首先要保证高效的读写(这里我联想到了数据库55555),所以我可能会选择使用平衡二叉树这样的数据结构来保存数据。
追问:这样的数据结构在我看来不是最优解,有没有想过使用哈希表来进行实现?
答:(这里犯了迷糊,反问面试官哈希表是不是指数组+链表)
追问:你认为的哈希表是什么?
答:哈希表的核心是哈希函数,通过哈希函数将键值对中的键进行映射,通过一些数据结构来进行保存。
追问:你聊到了哈希函数,那我们知道有哈希函数就不可避免地会产生哈希冲突,那你有了解过怎么解决哈希冲突吗?
答:我所了解到地解决哈希冲突方式有两种,第一种就是使用数组+链表这样地存储方式,如果产生了哈希冲突,我们还是将键值对放进数组的对应位置,只不过这个位置上存储的是一个链表,我们可以利用头插法或者尾插法将键值对插入到链表中去进行保存;第二种是当检测到哈希冲突的时候,我们从当前位置开始往后检测,直到检测到一个空位进行保存。(忘了两种方法名字叫什么了)
追问:那你认为,使用哈希表和使用二叉树来实现,哪种效率更高?
答:使用哈希表时,采用数组+链表这种数据结构的话,查找和插入效率都是O(1),在极端情况下,查找效率可能会退化为O(n),使用二叉树的话, 其插入和查找效率都是在对数级,因此,在哈希冲突发生概率不大的情况下使用哈希表效率要高一些(全程在想HashMap555)
3. 数据库
问:了解过Mysql索引吗?
答:了解一些
追问:那你知道Mysql索引为什么不采用二叉树而采用B+树吗?
答: B+树因为有多分支,避免了二叉树在数据量过大的情况下高度过高的情况,能够降低查找时间,另外,使用B+树能够很快的确定范围查找时的数据范围。
追:(面试官太好了,还帮我补充一下知识)其实还有一种情况,和操作系统有关,就是在操作系统中有页读取机制,使用二叉树当节点过多时,会造成过多的页切换,从而降低效率。
4. HTTP协议
问:你能介绍一下HTTP协议吗?
答:HTTP协议是一个无状态的协议,本次请求和之前的请求无关。它是一种报文交换格式的约定,规定了响应码、请求头、请求方法等内容,比如说常用的GET、POST、DELETE、PUT请求等,为了解决HTTP请求的无状态,我们通常会使用服务端的会话管理机制或者COOKIE来追踪客户端状态,对于响应码,有多种响应码表示不同的响应状态,比如正常响应是200,302重定向、404资源不存在、500服务端错误等。HTTPS是HTTP的安全版本,具体安全机制的实现方案不太了解(非计算机专业),但是了解其安全加密方案是基于公私钥的加密方案。
5. JSON交换格式
问:看到你在微信小程序中使用了JSON交换格式,有了解过JSON的数据格式吗?
答:具体的数据类型没有太了解,因为使用JAVA后端,直接将其作为字符串进行处理,在我看来,JSON数据格式和JS的对象比较类似,有键值对、数组以及内嵌的对象等等。
追问:你在使用JSON的过程中有遇到什么坑吗?
答:有,是在微信小程序使用ajax与后端交互过程中,当发送post请求传输参数给后端时,后端SpringBoot会出现不支持的媒体类型这样的错误,根据官文,需要在请求头中加入‘Content-Type’字段,后来的解决方案是请求头加入'Content-Type'字段,SpringBoot对每个请求的参数封装成Bean接收请求参数。
6. 编程语言基础
问:你介绍到在大学学习过C/C++,那么C/C++在运行的时候需要先进行编译才能运行,那么你了解过编译过程中发生了一些什么吗?
答:(内心OS:我用的是Java呀,C/C++也没怎么用啊,编译原理我也不是计算机的我也没学过啊)因为我平常项目开发用Java比较多一点,而且学校学到的C/C++仅限于程序设计,所以不太了解(GG)
追问:那你总应该了解栈吧,能聊聊程序运行过程中有哪些地方用到了栈吗?
答:方法调用
追问:那你能详细说一下方法栈存储了哪些信息吗?
答:返回地址,参数列表等
追:(面试官真的太好了,看我为难又来给我补充了)其实就你刚刚说的方法栈,它里面存储有很多数据,我们称为上下文,当然返回地址,参数列表这些也在其中。
7. 进程和线程
问:操作系统里面有两个概念是进程和线程,你能说说他们的区别吗?
答:线程是操作系统调度的最小单元,线程需要依附于进程存在,当一个进程中没有线程在运行,进程也就死亡,线程由进程派生,多个线程共享进程的资源,多个进程共享内存地址空间,线程也可以有自己的局部变量。(感觉很多都没答上来,估计是凉了)
问:那你刚刚说的方法栈是线程共享的还是私有的?
答:私有的。
8. 编程题
- SQL
有一张product表,product(id, title, category, sub_category),索引index(sub_category, category),写一条SQL来查询product表中category = 10并且sub_category = 10010的数据
答:select * from `product` where `sub_category` = 10010 and `cate_gory` = 10;
问:为什么要把sub_category放在这里
答:因为要符合索引的最左匹配原则
问:那把sub_category的查询条件改成大于10010,这条语句还能走索引吗?
答:(实在没想明白)能
问:那把category的查询条件改成大于10呢?
答:(依旧没想明白)不能 - 算法
(面试官说要给我找一道稍微简单一点的,但是我还是错了好多次,而且感觉这道题之前见过,有更简便的做法,但是我忘了,所以这道题大概率凉了)
给你一个32位无符号整型数字,请你将其按照二进制位反转之后输出:#include <iostream> using namespace std; int main() { unsigned int n; cin >> n; unsigned int ans = 0; for (int i = 0; i < 32; i++) { int mod = n % 2; ans = ans * 2 + mod; n = n >> 1; } cout << ans << endl; return 0; }
这道题最重要的注意点是要用unsigned,我就是忘了使用unsigned,结果调试了半天没调试出来为什么错了,浪费了好多时间。仔细审题啊
还有就是总感觉这道题有使用位运算的更简便的算法,之后再去查一查。