今年春招补招与暑假实习即将开始,有简书的粉丝私信问我校招的短期复习规划;还有些21届的研究生想搞研发,但实验室做算法,问我如何权衡;又或者对秋招过程中出现的一些问题很迷茫,出现了瓶颈觉得自己无法突破...这些问题我在复习备战的时候曾经都遇到过,有一些自己的心得,在之前的文章中也有写,只是大家可能没有耐心仔细看。在这篇文章中最后做一次全面的汇总,文中的部分内容与之前的文章会略有重复,但也会有新的内容需要大家好好理解消化...ψ(*`ー´)ψ
秋招分析与个人概况
首先阐述一下我的个人基本情况。本科湖北工业大学软件工程,硕士哈尔滨工业大学计算机技术,在19年的暑假提前批中拿到了字节跳动(sp,深圳 + 今日头条研发服务端部门)、百度(北京 + Java 开发工程师)、小米(北京 + Java 开发工程师)、华为(口头15级,深圳 + 通用软件工程师)和猿辅导(北京 + 服务端研发工程师)的 offer。
今年,或者说最近几年,计算机专业的校招形势比较严峻。算法岗的泡沫越来越小,平均工资趋向与研发岗持平,导致今年算法转研发的很多,但某些大厂的算法还是一骑绝尘。前端和客户端竞争稍小一点,但由于今年经济形势整体不太景气,所以比之前几年都更难找。
我现在所在的实验室是做 cv 的,所以研一开始入门深度学习的基础知识,包括看网课和学习配环境跑模型。由于平时比较关注牛客网、脉脉这一类信息流中有关互联网前沿的求职动向,所以对当前的就业形势有一个大致的预估。感觉大环境有些浮躁,搞算法,特别是机器学习、深度学习,要么偏研究,发论文,要么偏应用,算法落地。而且对我来说,深度学习就像炼丹,各种 tricks 排列组合,然后 train 模型,炼来炼去提升性能,然后发文章...可能本身科研能力也一般,所以并没有很深的体会或者对科研抱有很高的热情,只是觉得有时候算法落地还是挺难的,很多论文的实验复现后效果并不太理想。而且算法工程师首先得是一个工程师,自认为离一个真正的工程师还有一定的距离,于是选择了研发这条路,继续提高自己的 coding 能力和工程应用能力。
由于平时实验室也没有太多的活需要去完成,导师也很好比较信任我,让我可以按照自己既定的计划去学习,一方面花早上的时间去看一些比较繁琐费脑的文献,一方面花下午和晚上的时间复习秋招的基础知识或者刷题、准备面试项目,也还算游刃有余。
后端基础知识
研发需要掌握的知识点很广,作为一个应届生想要面面俱到不太现实,但一定要能在面试官面前展现出扎实的基础、对业务的理解能力和较强的 coding 实现能力,至于项目是不是高大上,他们并不会太在意。
Java 基础主要包括但不限于以下内容:
容器:
- ArrayList、Vector、TreeMap 的底层实现原理
- HashMap 的所有属性和方法底层实现、hash 的实现、怎样扩容、与 HashTable 的区别
- ConcurrentHashMap 做了哪些改进
- JDK 1.7 与 1.8 这些容器的底层有什么变化和区别,有哪些改进
并发编程:
- 线程的状态和方法、线程池的参数和实现原理、线程池的使用与注意事项
- synchronized 的实现原理
- Java 的锁机制与锁优化
- volatile 的特点
- CAS 更新的原理与存在的不足,怎样解决
- Java 内存模型
- 常见的 J.U.C 工具类,原子类的底层原理
- ThreadLocal 原理与内部数据结构
- Lock、AQS、Condition、与 synchronized 的对比
数据结构与算法:
- B+ 树的定义和应用场景
- 红黑树的定义和特点
- 二叉树的前中后序遍历非递归算法
- 字典树
- 并查集
- BFS + DFS
- 贪心算法
- KMP 算法
Java 虚拟机:
- JVM 内存结构
- 垃圾回收算法与垃圾收集器
- 内存分配策略
- 类加载机制的过程、双亲委派模型以及应用
框架:
- Spring IOC 容器的初始化过程
- AOP 面向切面的原理
- Spring 中运用了哪些设计模式
- SpringMVC 的工作原理
- MyBatis 中的 DAO 接口和 XML 中的 SQL是如何建立联系的
MySQL:
- 事务的四大特性、三种现象(脏读、不可重复读和幻读)的定义以及隔离级别
- 版本链的概念以及 MVCC
- 数据库引擎的格式以及内部实现机制、不同引擎之间的对比
- 存储引擎的页结构
- 数据库索引
- 数据库锁机制
- 分库分表方案
进阶知识完善(并不是必需,但面试知道这些会加分很多):
- 分布式相关概念:CAP、BASE 理论
- Zookeeper 的定义以及层次结构、集群和选举过程、应用场景
- Redis 的数据结构、持久化机制、集群、选举方式、应用场景
- 如何保证 Redis 的高并发和高可用
- Redis 持久化的优缺点
- 一致性 hash 算法
- 缓存穿透、雪崩和击穿的定义和解决方案
- 如何保证缓存与数据库的双写一致性
- 常见的消息队列及作用
- 如何保证消息队列的高可用
- 如何保证消息的幂等性和可靠性传输
上面的内容大致上是按照我秋招过程中总结的思维导图大纲罗列出来的,看上去虽然并不是很多,但在复习的时候,会发现很多问题。当你复习 A 模块的时候,你需要知道 B 模块的内容,不同知识有区别也有相似的地方,很多知识都是串起来的,是一个体系。如果把以上内容做到熟能生巧心中有数,面试这一环节中的所有跟基础有关的问题基本上都能答出来。
适合此阶段看的计算机书籍有(排名不分先后):《疯狂 Java 讲义》、《深入理解 Java 虚拟机》、《Java 编程思想》、《Java 并发编程的艺术》、《Redis 的设计与实现》。每本书不必从头读到尾,当成一个工具书或者宝典,对一些存疑的地方可以有针对性地去查阅,当然有些比较重点的知识(容器、并发)还是按章节去读,知识才能形成一个整体。
coding 能力
刷题这件事,需要好好重视。19年实习 + 秋招我大大小小参加了十几场笔试,一般都是2小时4-5道编程题,平均半小时一道,时间还是比较紧的。而且在那种竞争压力下,难免思路上会出现一些障碍,因此需要平时刻苦的训练。
很多人刷了一些题,发现不仅以前刷过的忘了,而且碰到新题也不会做,感觉怎么也突破不了。这种情况我也遇到过,也让我苦恼了一段时间。解决方法就是做过的题反复做。我从18年底开始刷剑指 offer 和 LeetCode,一直到19年暑假提前批,大概半年左右的时间,剑指67题 + LeetCode 接近400题 + 牛客网互联网真题,基本都是三刷,总题量有一两千。其中 LeetCode 的题目是按照 GitHub 上的面试精选分类从头刷到尾,包括字符串、树、图、数学、暴力、贪心和动规等方面的内容。
第一遍基本上相当于熟悉基本的输入输出和笔试的出题风格,虽然之前搞过蓝桥杯和 ACM 的短期训练,但过了很长时间比较生疏,很多题对我而言相当于是全新的,第一次啃完这些题,时间最长,花的精力也最多。
第二遍是熟悉解题套路,比如迷宫就是 bfs/dfs,top K 就是堆/排序,K th 就是 partition/排序,分硬币/找钱/最长公共子序列就是 dp 等等,毕竟是以面试为导向的题库,不像 ACM 那样技巧性很强,很多题的公共思想都是相通的,因此基础题要牢牢掌握,在真正笔试的时候很多题其实就是在这些基础题上加一个背景,比如拼多多的“多多干了什么事”、腾讯的“小Q又干了什么事”,只要仔细读题理解完背景本身,再去思考之前做过的套路中哪一个最合适就行。
第三遍是练思维能力、练手速。训练迅速写好输入输出框架的能力,训练从题目背景中提取算法模型的能力,训练从记忆中提取合适解题套路的能力,训练迅速找出边界测试数据修复代码中 bug 的能力。
做完这些,笔试和面试中的手撕代码应该没有很大的问题。今年秋招中几家大厂的面试手撕代码,我都碰到了几个与 LeetCode medium 题类似的题目,在短时间内找出了最优解,还算比较幸运。克服过程的枯燥并坚持,结果不会差。
项目
我在简历中罗列的项目比较水,但也并不是像一些人 fork 完别人的 GitHub repository,跑通代码,知道有哪些功能就万事大吉。比如秒杀平台,大多数人都会考虑如何解决超卖现象、Redis 实现缓存提升性能,但有没有想过怎样保证秒杀请求的可靠性?怎样保证消息的幂等性?如果在分布式环境下如何再优化…这都是可以自己去思考的问题。
其实不管我们做的是什么项目,在面试官眼里都是很 low 的,那么在这个前提下,如何让对方看出你的与众不同,这就是你需要思考的地方。比如展现出你在项目中对业务逻辑的认识、如何优化使得并发量有一个提升、对项目中出现的 bug 是怎样定位和解决的...这些东西作为一个没有实习过的人来说想掌握好不太容易,我在面阿里菜鸟的时候,由于实习有挂面记录,再加上项目的一些实战经验不是很充足,所以吃了不少亏...
结语
今年的提前批比较幸运,准备得比较早,投简历也比较早,及时上车,可能晚一点就没有hc了,找工作除了实力也需要运气,更是一个持久战,一场战斗,主要还是打法和迎难而上的勇气。今年很多公司缩招,要是我一直犹豫不敢投简历,说不定就没机会了。至于打法,得益于自己平时一直都是按照经过自己深思熟虑后的学习计划一步步走,从语法到基础,再到进阶,通过一次次面试实战积累经验、总结技巧,最终取得了久违的胜利。
越好的东西越值得等待,希望大家能坚持每天输入,坚持总结,坚持刷题,平常心发挥,积累经验,多拿 offer。