每年的八九月份,校招笔试就像潮水一样涌过来。我前几天刚陪一个学弟复盘完他的秋招流程,翻到58同城2023校招后端岗的笔试题时,觉得这套题放在今天看依然有很强的参考价值。它不偏不怪,题型覆盖很典型,从数据结构、算法到JVM、MySQL、网络,再到项目问答,基本把后端校招笔试该踩的点都踩了一遍。这篇文章就把我当时整理的高频考点、实战思路和复盘过程写出来,给正在准备后端点岗位的同学做一份参考地图。
1. 笔试形态与考点布局:这套题在考什么
先说结论:58同城这套后端校招笔试,整体难度属于中等偏上,但不会故意卡人。它更看重基础是否扎实、算法能不能一遍写对、遇到问题有没有清晰的排查思路,而不是追求偏题怪题。
1.1 题型构成与时间分配
我拿到的这套试卷,题型大致分成三块:
| 题型 | 题量 | 建议用时 | 考查方向 |
|---|---|---|---|
| 单选/多选 | 20道左右 | 25分钟 | 计算机基础、Java基础、数据库、网络 |
| 编程题 | 2道 | 50分钟 | 数据结构与算法、编码能力 |
| 问答/设计题 | 1~2道 | 25分钟 | 项目经验、系统设计思路 |
整体时间一般是90分钟到100分钟。这个分配很关键,我见过不少同学在选择题上纠结太久,导致编程题没写完。我的建议是选择题严格控制时间,一道题超过一分半还没思路就先标记跳过去,先把后面的大头分数拿稳。
1.2 考点分布与优先级判断
从真题反馈和我自己刷题的经验来看,考点能分成几个梯队:
第一梯队是数据结构与算法,占比最高,也最拉分。链表反转、二叉树遍历、TopK问题、字符串处理、DFS/BFS、动态规划,都是高频出现的老朋友。
第二梯队是Java基础和数据库。Java这边,集合类源码、HashMap底层、并发编程、JVM内存模型是必考重点。数据库就是索引、事务、锁,还有SQL手写。
第三梯队是计算机网络、操作系统和Spring框架。网络重点在TCP三次握手四次挥手、HTTP状态码、HTTPS流程;操作系统重点在进程线程、死锁、内存管理。
这里提一句:复习的时候别平均用力。算法和Java基础如果不够熟,性价比最高的是先死磕这两块。网络和操作系统可以放到后面用刷题的方式快速过,框架类只要准备几个高频问题就够了,笔试一般不会深挖Spring源码。
2. 算法编程题实战复盘:从题意到AC的完整链路
算法题是整套卷子的得分大头,也是很多人的心理阴影。我复盘了当时遇到的题目和后来整理的高频题,选两道最典型的来拆解。
2.1 链表题:反转链表的变体思路
有一道题是“反转链表中第m到n个节点之间的部分”,这道题是力扣92题的变体。它比全链表反转多了一个边界条件处理,很能考出基本功。
解题思路分三步走:
- 建一个哑节点dummy,指向头节点,避免头节点被反转时需要特殊处理。
- 找到第m个节点的前驱节点pre,这一步需要先走m-1步。
- 进行m到n区间的局部反转,反转方法和普通反转链表一样,只是要控制反转次数为n-m次。
代码核心段大概是这样的思路:
ListNode dummy = new ListNode(0); dummy.next = head; ListNode pre = dummy; for (int i = 0; i < m - 1; i++) { pre = pre.next; } ListNode cur = pre.next; for (int i = 0; i < n - m; i++) { ListNode next = cur.next; cur.next = next.next; next.next = pre.next; pre.next = next; } return dummy.next;这里的核心技巧是用pre.next作为每次插入位置的指针,不需要记录太多临时节点。我一开始写链表题喜欢维护一堆临时变量,后来发现越简洁的写法越不容易出错。
2.2 TopK问题:堆排与快选怎么选
另一道高频题是“求数组中第K大的元素”。这道题有两个主流解法,很多人在笔试时纠结选哪个。
用堆排序的思路,维护一个大小为K的小顶堆,遍历数组,堆顶就是第K大的元素。时间复杂度O(nlogK)。笔试时用Java的话,直接PriorityQueue就能实现,代码量不大,建议优先选这个方案。
PriorityQueue<Integer> heap = new PriorityQueue<>(k); for (int num : nums) { if (heap.size() < k) { heap.offer(num); } else if (num > heap.peek()) { heap.poll(); heap.offer(num); } } return heap.peek();如果用快速选择算法,平均时间复杂度是O(n),但最坏情况会退化到O(n²)。笔试现场如果对快排的partition过程不够熟,我不建议冒险用快选,因为边界条件一旦写错,调试起来很浪费时间。堆排虽然复杂度常数大一点,但胜在稳定可靠。
2.3 编码环节的提分细节
代码能AC是一回事,代码能不能让面试官“觉得你行”是另一回事。笔试系统虽然不会直接看代码风格,但很多公司的笔试题会和后面的面试官共享,你写的代码面试官是能看到的。这里有几个细节值得注意:
- 变量命名别用a、b、c这种,用meaningful的名称,比如pre、cur、visited、count,一眼能看懂作用。
- 循环边界条件写清楚,不管是i < n还是i <= n - 1,保持全篇一致。
- 能加注释的关键逻辑加一行注释,表明你确实理解这段代码在做什么。
- 写完自查一遍边界条件:空数组、只有一个元素、K超过数组长度,这些情况代码能不能正确处理。
3. 计算机基础选择题考点拆解:八股文的正确打开方式
选择题部分看起来知识点很散,实际上还是有规律可循的。我按Java、数据库、计网、操作系统四个方向来梳理。
3.1 Java基础:集合类源码与并发JUC
Java基础里最常考的还是HashMap和ConcurrentHashMap。HashMap的底层数据结构、put流程、扩容机制、红黑树转换阈值,这些是每年校招的保留曲目。可以结合源码去记,不要死背结论。
比如HashMap在JDK8的put流程,我会这样给自己讲一遍:先算key的hash,通过扰动函数让高位也参与寻址,然后看table数组对应位置是不是空。如果是空就直接插入;如果有值就拉链,链表长度超过8且数组长度到达64就转红黑树。扩容时JDK8的优化是,元素要么留在原位,要么移动旧容量大小到新的位置,不需要重新计算hash。
并发这块,synchronized和ReentrantLock的区别、volatile的可见性和有序性、ThreadLocal的内存泄漏问题、线程池的核心参数和拒绝策略都是高频考点。线程池的参数一定要记清楚:corePoolSize、maximumPoolSize、keepAliveTime、workQueue、threadFactory、handler,缺一不可。还有线程池的提交流程:先判断核心线程、再往队列里塞、再判断最大线程数、最后走拒绝策略。
3.2 数据库:索引、事务与锁机制
数据库这块,索引是绝对重点。聚簇索引和非聚簇索引的区别、联合索引的最左前缀原则、回表、覆盖索引、索引失效的场景,每个都值得花时间整理成自己的笔记。
我复习索引时习惯用一套自己的话术去理解:聚簇索引就是数据本身按索引顺序存储,叶子节点直接存整行数据;非聚簇索引叶子节点存的是主键值。回表就是先查非聚簇索引拿到主键,再用主键查聚簇索引拿数据。覆盖索引就是查询的字段本身就在索引里,不用回表,性能好。索引失效的常见场景包括:对索引列用了函数或计算、隐式类型转换、like以通配符开头、联合索引不满足最左前缀。
事务隔离级别和MVCC也是一定要掌握的。四个隔离级别——读未提交、读已提交、可重复读、串行化,对应的脏读、不可重复读、幻读问题,MySQL默认是可重复读,但InnoDB通过间隙锁和MVCC解决了部分幻读问题。这些内容最好能在理解的基础上自己讲一遍,而不是背概念。
锁机制方面,全局锁、表级锁、行级锁、间隙锁、临键锁的区别和应用场景要能分清楚。尤其是临键锁,它是行锁和间隙锁的结合,InnoDB默认的隔离级别下范围查询会用临键锁来防止幻读。
3.3 计算机网络:TCP与HTTP高频点
网络这块,最常考的还是TCP。三次握手和四次挥手的状态变化要像背电话号码一样熟:SYN_SENT、SYN_RCVD、ESTABLISHED、FIN_WAIT_1、FIN_WAIT_2、CLOSE_WAIT、LAST_ACK、TIME_WAIT、CLOSED。
TIME_WAIT这个状态值得多说一句,因为它经常被追问。主动关闭连接的一方会进入TIME_WAIT状态,等待2MSL后才彻底关闭。为什么要等2MSL?两个原因:第一,要保证最后一个ACK能到达对端,如果对端没收到会重发FIN,这个时间段内还能响应;第二,让本连接产生的所有报文段都能从网络中消失,避免污染后续的连接。
HTTP这边,状态码的语义要记清楚,尤其是301和302的区别,401和403的区别。301是永久重定向,302是临时重定向;401是未认证,403是服务器理解了请求但拒绝执行。HTTPS的握手过程,重点是SSL/TLS握手,客户端和服务端怎么交换证书、怎么协商对称密钥,也要能画出来讲一遍。
3.4 操作系统与Linux:并发三板斧
操作系统选择题常考的是进程和线程的区别、进程间通信方式、死锁的四个必要条件、页面置换算法、虚拟内存。
进程间通信方式总结下来就是八种:管道、FIFO、消息队列、信号量、共享内存、信号、socket、eventfd。面试秋招问到最多的是管道和共享内存的区别。管道是内核缓冲区,单向流动,适合父子进程或兄弟进程;共享内存是最快的IPC方式,但需要同步机制配合。
死锁四个条件——互斥、持有并等待、不可剥夺、循环等待。破坏任意一个都能避免死锁,比如资源一次性分配破坏持有并等待,允许抢占破坏不可剥夺。
Linux命令这块,常考的有查看端口占用netstat -tlnp、查看进程ps -ef、查看内存free -m、磁盘df -h、日志查看tail -f。还有grep、awk、sed这三个文本处理三剑客,笔试不一定现场让你写,但后面的面试大概率会问。
4. 项目问答与系统设计题:让开放题变成送分题
58同城的笔试后面还附带简答或设计类题目,通常是让你聊一聊自己做过的项目,或者给一个场景让你设计方案。这类题目看起来开放,其实有固定的回答框架。
4.1 项目介绍:STAR法则的实战应用
项目介绍题,推荐用STAR法则来组织回答:情境、任务、行动、结果。但更要提醒一个常见误区:很多同学介绍项目时只讲功能,不讲技术难点和思考过程。面试官想听的不是“我实现了登录注册”,而是“我在实现登录注册时遇到了什么问题,是怎么排查和解决的”。
举个例子,假如项目里有用户登录模块,别只说用了JWT。你要能讲清楚:token过期了怎么处理、用户退出登录怎么让token失效、多端登录怎么控制、密码加密用的什么方案、为什么不用MD5而用BCrypt、接口被刷了怎么防。这一层一层追问下去,才是项目经验真正的含金量。
还有一个经验是,准备项目时可以提前列出“面试官可能会追问的10个问题”清单。比如:
- 这个项目的并发量大概多少?你做过压测吗?
- 数据库表怎么设计的?索引怎么建的?为什么?
- 如果某个接口响应很慢,你会怎么排查?
- 如果数据库数据量翻十倍,你的方案还能撑住吗? 把这些问题提前准备好,回答的时候就不会慌。
4.2 设计题:先定边界再谈方案
开放设计题通常是类似“设计一个短链接系统”或者“设计一个秒杀系统”的题目。这种情况下,最重要的是展现你有结构化的思考,而不是一上来就堆技术名词。
我的回答框架是四步走:
第一步,明确需求边界。先问清楚是面向C端还是B端,预估的QPS是多少,数据量多大,是否需要强一致。这些信息不同,方案可以完全不一样。
第二步,定义核心接口。短链系统就是两个接口:生成短链和跳转长链。秒杀系统就是预减库存、创建订单、支付回调。
第三步,画数据模型。短链系统的核心表就是短链映射表,字段包括短码、长链接、创建时间、过期时间。要考虑短码生成算法,比如发号器或者哈希截断。
第四步,考虑性能与扩展性。加缓存、削峰、限流、异步化,把这些关键词落到具体的实现方案里。
这套框架的好处是,即使你对某个技术方案不熟悉,也能让面试官看到你思考问题的完整性。毕竟设计题考察的核心能力不是“背过多少方案”,而是“面对模糊问题,你能不能一步步拆解”。
5. 笔试现场时间管理与应急策略
这一节聊聊现场发挥。很多同学笔试翻车不是因为不会做,而是因为节奏乱了。
5.1 不同题型的抢分顺序
我的实战建议是:先做编程题,再做选择题,最后做问答设计题。理由很简单,编程题要用的时间最长,而且代码写完之后可能会有编译错误、边界条件要调,这些都是不可控因素,越早面对越好。
如果你一到考场先慢慢做选择题,等到编程题的时候只剩20分钟,大脑很容易进入“急急忙忙写代码”的状态,明明能AC的题也可能因为粗心丢分。我有一场笔试就是这样,选择题用掉了40分钟,编程题差点没写完,从那之后每次都调整成先编程后选择的策略。
5.2 遇到不会的题怎么处理
遇到不会的选择题,先凭第一感觉选,然后打个标记。等所有题做完还有剩余时间再回来仔细想。不要在不确定的题上耗太久,时间成本太高了。
编程题如果卡住了,先写伪代码把思路理出来,再慢慢补全实现。有些笔试系统会按测试用例给分,如果只能过一部分用例,至少把你想到的正确部分的代码写上去,能拿一分是一分。空着肯定零分,写了可能还有部分分。
另外,笔试系统一般会提供本地编辑器和在线编辑器两种模式,这个要提前适应。在线编辑器没有代码提示、没有自动补全,平时如果只依赖IDE写代码,笔试时会非常别扭。我建议平时刷题就尽量在“不帮写代码”的环境里练,至少每周有一两天用纯文本编辑器写题,别惯着自己。
5.3 环境测试不能跳过
有个特别容易被忽视的坑:笔试前的环境测试。非技术岗可能无所谓,技术岗笔试如果摄像头、浏览器、网络出了问题,就直接废了。
我习惯提前至少半小时坐到电脑前,先测一遍摄像头,进笔试链接加载页面,测试编译器能不能正常跑通一个Hello World。这个操作能帮你过滤掉至少一半的意外状况。
6. 考后复盘与后续衔接:笔试不是终点
笔试结束只是第一步,后面还有面试。很多人考完就撒手不管,其实笔试后的复盘价值和刷题价值一样高。
6.1 怎么记录和整理笔试题
我建议每场笔试一结束,趁记忆还热乎,立刻把题目回忆出来,记到自己的题库里。不用写得很完整,能还原题目大意、你的解题思路、正确答案就行。关键是,一周以后重新做一遍,检验自己是不是真的掌握了。
比如你发现自己笔试时有一道动态规划的题没做出来,那就说明DP这块是你的薄弱环节。接下来两天不要干别的,就集中刷DP,从背包问题、子序列问题、股票买卖问题,一路刷到区间DP和状态压缩。带着问题去刷题,效果比漫无目的地一天刷十道强得多。
6.2 笔试与面试的知识复用
笔试里考的基础题,就是你面试时会被追问的题。我把笔试中反复出现的知识点和面试中反复被问到的知识点做了一个汇总表,你会发现两者高度重合。
| 知识点 | 笔试考法 | 面试追问方向 |
|---|---|---|
| HashMap | 底层结构、put流程的选择题 | ConcurrentHashMap分段锁还是CAS?扩容机制? |
| 线程池 | 参数选择、执行流程选择题 | 线程池大小怎么定?CPU密集和IO密集分别怎么设? |
| MySQL索引 | 索引失效场景、最左前缀选择题 | 覆盖索引和回表在项目里怎么用?慢查询怎么优化? |
| Redis | 缓存数据类型、过期策略选择题 | 缓存穿透、击穿、雪崩怎么解决?分布式锁实现方案? |
| TCP | 状态流转、字段含义选择题 | TIME_WAIT为什么是2MSL?TCP粘包怎么解决? |
笔试暴露出来的薄弱点,不用等到面试通知下来再补,当场复盘出来就当场补掉,后面找实习、冲大厂都省力很多。
6.3 心态建设:笔试的随机性远大于实力
最后说点掏心窝子的。早几年我准备校招时,把每一场笔试都当成生死战,结果崩了好几场。后来才想明白,笔试是一个概率事件:有的场次题目刚好是你的舒适区,有的场次全是你的盲区。同样水平的两个人,不同场次的笔试分数可以差出50%以上。
所以别因为一场笔试没考好就开始否定自己。正确做法是,把每一场笔试当成一次免费的模拟测试,考完看自己哪块弱,补齐就好了。校招季这么长,机会多的是,真正决定你能不能拿到offer的,是你能不能在一场又一场的考试中保持“发现问题→补弱点→再战斗”这个循环不中断。
准备后端笔试这条路没有捷径,但每一步都算数。把这篇文章里提到的考点吃透,再用三五场笔试练手,你会发现自己面对题目时越来越从容。祝刷题顺利,Offer到手。