
校招季一到后台问后端笔试题怎么准备的人就多起来。前几天整理旧电脑翻到当年搜狗2020校招后端笔试第二场的草稿纸和代码草稿那场考试让我印象很深题型不偏算法题难度中等偏上基础题几乎全是“你以为会、写的时候就卡壳”的陷阱。如果你现在也在准备后端校招这篇复盘会很对胃口——我会把整场笔试的题型构成、每道编程题的思路和代码、选择题背后的高频考点以及我自己在考场上踩过的坑一起拆开讲。先说明一点具体题目的字面我肯定记不全了下面还原的是当时考场上见到的题型和同级别考点不是官方原题但对准这套卷子的风格去复习方向不会错。1. 先说说这场笔试的整体体感题型分布与时间压力1.1 题型构成三个模块的实际比重搜狗这场后端笔试给我的第一感觉是“杂而稳”。整套卷子大致由三块组成不定项选择题、编程题、以及少量偏工程场景的简答题。选择题约占40分编程题是大头四道题目从易到难排列最后一道明显是用来区分人的。选择题部分单选和多选混在一起多选少选不得分这点很坑。我身边好几个同学不是不会做而是多选漏选——明明知道正确答案因为不确定就没勾白白丢分。考察范围基本锁死在C/Java语言基础、操作系统、计算机网络、数据库、数据结构与算法这些后端基本功上没有出现偏门的前端题或运维题整体出题风格还算友好。编程题四道覆盖了字符串处理、栈应用、动态规划、并查集/图论这几类典型题型。难度排序大概是字符串压缩这类简单题在前中间一道括号题或回文串题最后一道图论题压轴。这个设计思路很常见——先给你送分题稳住心态再用中间题筛掉只会背模板的人最后用压轴题挑出真正有工程思维的学生。1.2 时间分配策略编程题先做还是后做我当时的策略是拿到卷子先用5分钟把所有题目扫一遍给编程题按难度做个快速标记。这个动作建议每个人都要做千万别拿到题就从第一题开始闷头写因为选择题里很可能藏着短时间内根本想不通的题目跟它死磕会直接压缩编程题的时间。我的实际分配是选择题控制在15到20分钟内完成拿不准的先标记不纠结然后立刻转去写编程题中一眼就有思路的两道题先把基础分拿稳最后再回头啃难题和被标记的选择题。这套节奏不一定适合所有人但有个原则不会错编程题的代码尽量先写因为代码写完需要调试而选择题即使最后时间不够蒙一个选项也有概率得分。把时间留给能产生确定性产出的编程题永远比卡在一道多选上划算。1.3 在线笔试平台的几个隐藏坑搜狗那年用的在线测评平台不是本地IDE代码只能在一个简陋的网页编辑器里写。这个环境有几个坑我第一次参加校招笔试时全踩过编辑器没有自动补全常用的头文件、API名称最好记牢不然写STL容器时到处卡壳。输入输出必须严格按题目要求来多打印一行提示信息都可能被判错。有些平台连cout 请输入n这种提示都不会容忍。有些编程题会提供多组测试数据输入格式可能包含多余空格或空行代码里最好用cin n而不是getline去读避免被换行符坑到。交卷前一定要确认代码能编译。哪怕是对的部分只要有编译错误整道题就是零分这个损失太大了。吃过亏之后我后来每次笔试前都会提前去对应平台做一套模拟题熟悉编译环境和输入输出格式这个准备工作能帮你在考场上省下至少10分钟。2. 编程题复盘四道题的考点、思路与代码还原2.1 字符串压缩不要小看这种“简单题”字符串题是校招笔试的常客这场也不例外。有一道类似“字符串压缩”的题目给定一个字符串把连续重复的字符按字符出现次数的方式压缩比如aabcccccaaa变成a2b1c5a3。如果压缩后的字符串长度不小于原字符串则返回原字符串。这类题的本质是单次遍历加边界处理看起来简单但它考察的点恰恰是最容易忽略的最后一个字符的计数怎么收尾。#include iostream #include string using namespace std; string compressString(string S) { if (S.empty()) return S; string res; int count 1; for (int i 1; i S.size(); i) { if (i S.size() S[i] S[i - 1]) { count; } else { res S[i - 1]; res to_string(count); count 1; } } return res.size() S.size() ? res : S; }这里的循环条件i S.size()是核心技巧当i S.size()时循环会进入else分支把最后一组连续字符写进结果。如果你写成i S.size()遍历结束前会少处理最后一组字符。考场上很多人不以为意写完直接提交结果在小样本数据上没问题跑到边界测试就崩。最好在纸上先跑一遍单字符字符串、空字符串、全相同字符字符串这三类情况确认不会出错再交。2.2 最长有效括号栈解法为什么比动态规划好写中间难度的一道题是“最长有效括号”给定一个只包含(和)的字符串找出最长的有效括号子串长度。比如)()())的结果是4。这题有两个主流解法动态规划和栈。我当时优先写栈因为栈的思维更贴近“括号匹配”这个直觉代码也更不容易写错。#include iostream #include string #include stack using namespace std; int longestValidParentheses(string s) { stackint st; st.push(-1); // 栈底始终保存“最后一个未匹配的右括号位置” int maxLen 0; for (int i 0; i s.size(); i) { if (s[i] () { st.push(i); } else { st.pop(); if (st.empty()) { st.push(i); // 当前右括号未匹配作为新边界 } else { maxLen max(maxLen, i - st.top()); } } } return maxLen; }栈里存的是下标而不是字符这是整个解法的关键。初始化时压入-1作为虚拟边界当遇到右括号时先弹出栈顶如果栈空说明当前的右括号没有匹配的左括号它就成为新的边界如果栈不为空i - st.top()就是当前有效子串长度。这个解法的时间复杂度和空间复杂度都是O(n)。面试里如果被追问能不能优化到O(1)空间可以提一下双指针正反扫描的解法但笔试阶段能写出栈解法已经足够稳。2.3 最长回文子串中心扩展法的复杂度分析回文类题目在后端笔试出现频率很高因为状态转移和边界条件都很有讲究。这道题我当时用了中心扩展法把每个字符当成回文中心向两边扩展。注意要分别考虑奇数长度和偶数长度两种中心比如aba的中心是b而abba的中心是bb中间那条缝。#include iostream #include string using namespace std; string longestPalindrome(string s) { if (s.empty()) return ; int start 0, maxLen 1; for (int i 0; i s.size(); i) { int len1 expandAroundCenter(s, i, i); // 奇数长度 int len2 expandAroundCenter(s, i, i 1); // 偶数长度 int len max(len1, len2); if (len maxLen) { maxLen len; start i - (len - 1) / 2; } } return s.substr(start, maxLen); } int expandAroundCenter(string s, int left, int right) { while (left 0 right s.size() s[left] s[right]) { left--; right; } return right - left - 1; }中心扩展法的时间复杂度是O(n^2)空间复杂度O(1)对校招笔试来说复杂度够用。有的同学一上来就背Manacher算法我反而不建议因为O(n)的Manacher边界判断多、容易写错笔试现场一旦调试不过就是灾难。能快速写出一个正确性有保障的解法比硬憋一个高级但写不完的解法强得多。我当时在这道题上犯的一个小错误是计算start时把减1的位置搞混导致substr截错了位置。你写完代码后用babad和cbbd这类例子实际跑一遍比肉眼检查靠谱。2.4 并查集连通分量考的是工程思维压轴编程题是一道和“连通分量”相关的图论题给定n个节点和m条边判断图中有多少个连通分量。这类题的本意不是让你深搜广搜而是考察并查集——一种把动态连通性问题处理得干净利落的数据结构。#include iostream #include vector using namespace std; vectorint parent; int find(int x) { if (parent[x] ! x) { parent[x] find(parent[x]); // 路径压缩 } return parent[x]; } void unionSet(int x, int y) { int rootX find(x); int rootY find(y); if (rootX ! rootY) { parent[rootX] rootY; // 简单合并未做按秩合并 } } int main() { int n, m; cin n m; parent.resize(n 1); for (int i 1; i n; i) parent[i] i; for (int i 0; i m; i) { int u, v; cin u v; unionSet(u, v); } int count 0; for (int i 1; i n; i) { if (find(i) i) count; } cout count endl; return 0; }写并查集最容易犯两个错一是union之前没有先find直接把父节点拼过去导致树结构被破坏二是路径压缩时忘记用递归或者迭代更新parent[x]。我当时还忽略了带路径压缩的find如果写成非递归版本需要手动把整条路径上的节点全部指向根节点否则部分节点会滞后更新。校招笔试考并查集其实不只是考一个模板而是看你能不能把“连通性”这个抽象概念落地成代码。遇到这类题先把模板写在草稿纸上再根据题目要求做变形会稳很多。3. 基础题后端笔试里那些“以为会、一做就错”的考点3.1 C/Java语言基础与内存管理选择题里C和Java的基础知识占了很大篇幅。C部分常考虚函数表、构造函数析构顺序、栈上对象和堆上对象的区别、深拷贝浅拷贝Java部分常考String不可变性、HashMap底层原理、垃圾回收的可达性分析。我印象最深的一道多选是问“关于虚函数描述正确的是”。里面有个选项说“虚函数可以提高调用效率”这其实是错的因为虚函数通过虚函数表间接调用比普通函数多一层跳转正常情况下性能只会更低不会更高。很多同学一看到“虚函数”就习惯性认为和“多态”“高级”挂钩顺手选了结果就中招。这类题考的不是记忆而是你是否真的理解背后的机制。复习的时候我建议做一个动作每遇到一个结论都追问自己一句为什么。比如String为什么不可变因为不可变才能实现字符串常量池复用才能保证哈希值不变线程安全也是附带收益。能这样往下挖一层多选漏选的概率会低很多。3.2 操作系统进程、线程、死锁与内存分页操作系统在后端笔试里是必考模块尤其搜索公司对并发、内存这类底层机制非常看重。高频考点包括进程与线程的区别、死锁的四个必要条件、用户态与内核态的切换开销、虚拟内存与页面置换算法。有一道题考LRU和LFU的区别选项里有个描述是“LRU是淘汰最近最少使用的页面LFU是淘汰最久未访问的页面”。这个说法看着眼熟但后半句是偷换概念LFU是“访问频率最低”而不是“最久未访问”。做题时一定要抠字眼这种题就是专门用来筛掉记忆模糊的人。另外操作系统常和“后端调优”结合出题。比如线上服务响应变慢你通过top看到CPU使用率高但内存充足这个时候应该优先怀疑什么是Java进程里有大量计算密集型的线程还是频繁的上下文切换这个思路比单纯背概念更贴近后端岗位的实战要求。3.3 计算机网络TCP、HTTP与状态码细节网络基础题里TCP三次握手和四次挥手是必考。有一道题问TIME_WAIT状态出现在哪一端、为什么需要它。答案是主动关闭连接的一端要等待2MSL目的是确保最后一个ACK能到达对端同时让旧连接的报文在网络中消逝不会干扰新连接。HTTP状态码也是常客。301是永久重定向302是临时重定向304是Not Modified配合缓存使用。选择题里给了几个实际场景让你选状态码比如“用户访问的URL永久更换了新地址”应该返回什么答案自然是301。后端开发和HTTP打交道非常多这些状态码不只是八股线上排查问题时你会发现判断一个接口是浏览器缓存问题还是服务端问题第一步就是看状态码。复习时把状态码按1xx到5xx分好类再结合抓包工具实际看几次请求印象会非常牢固。3.4 数据库与Redis索引为什么用B树数据库题主要围绕索引机制和SQL优化。问到“为什么InnoDB用B树而不是红黑树”时得分点在于B树是多路平衡树树高更低磁盘IO次数更少所有数据存储在叶子节点且叶子节点用链表相连非常适合范围查询。还有一道题给了个SQL让你判断哪里会导致索引失效比如WHERE name LIKE %abc、WHERE age 1 20这类条件。核心原则是对索引列做计算或函数操作或者前导模糊匹配都会导致无法使用索引。我复习时把这些规则整理成了一张表格笔试前瞄一眼效果很好。Redis考的大多是数据结构与缓存问题。比如zset底层为什么是跳表跳表和平衡树的区别缓存穿透、击穿、雪崩分别怎么解决。这里有一个容易混淆的点布隆过滤器解决的是缓存穿透互斥锁和逻辑过期解决的是缓存击穿集群和过期时间错开解决的是雪崩。3.5 Linux与工程命令不背命令要背场景Linux命令题在搜狗这场笔试里也有出现但考法很务实——给一段服务器异常的描述让你选排查命令。比如“线上端口8000被占用怎么找出占用进程”答案是netstat -tunlp | grep 8000或lsof -i:8000。还有一个场景是“日志文件很大怎么统计某个关键字出现次数”grep 关键字 app.log | wc -l。这两个命令组合是后端日常排查命脉基本每天都会用到。复习Linux不要死记命令参数而是按场景整理查进程用什么、查端口用什么、查磁盘用什么、查网络连接用什么。每个场景准备一到两个命令笔试和面试都够用了。4. 我在草稿纸上的翻车现场三道典型错题复盘4.1 误以为 string 是 O(1)导致超时编程题里有一道字符串处理题我一开始用循环不断做res s[i]来拼接结果。当时觉得这个操作很自然完全没考虑到std::string在追加时如果容量不够需要重新分配内存并把原数据拷贝过去频率高了之后整体复杂度会接近O(n^2)。后来我改成先统计结果长度调用res.reserve(预估长度)预留空间再在循环里追加速度立刻提上来了。这个点其实反映出对STL底层实现的理解深不深——校招笔试里数据量大的用例往往就是用来筛掉这种隐藏低效写法的。4.2 多选漏选STL容器底层数据结构有一道多选题问vector、list、deque、map的底层实现和操作复杂度我少勾了“deque支持随机访问但中间插入是O(n)”。当时看到“随机访问”直接想起了vector觉得deque不是随机访问容器就放弃了。实际上deque是双端队列底层是分段连续空间支持operator[]随机访问复杂度O(1)但在中间插入元素需要移动数据复杂度O(n)。这类题考的是STL容器家族的能力图谱复习时把每个容器的底层、随机访问能力、头部/尾部插入删除复杂度、迭代器类型画成一张表比反复刷题更高效。4.3 字符串转整数的溢出判断漏写有一道和atoi功能类似的编程题我写的时候只考虑了正负号和非法字符忽略了整数越界。题目明确要求溢出时返回INT_MAX或INT_MIN我没加这个判断跑到大数据量的测试用例直接出错。正确的做法是每次算出新值之前判断res (INT_MAX - digit) / 10如果超过就直接返回边界值而不是等溢出后再想办法。这种题考察的不仅是基础语法更是“防御性编程”意识——后端代码面对的是不可信输入边界处理必须主动做。4.4 动态规划下标越界从1开始遍历时的边界最长有效括号还有另一种动态规划写法我当时顺着DP思路捋边界条件时发现很容易忘记判断s[i - dp[i - 1] - 1]这个下标是否存在。如果i - dp[i - 1] - 1跑到了-1数组就越界了。后来总结出一个习惯写完DP状态转移第一件事不是跑样例而是检查所有数组下标是否可能为负、是否可能超过数组长度。这类问题多方向展开之后边界条件很容易漏检查下标比检查业务逻辑优先级更高。5. 考完回头看这套卷子应该怎么指导你复习5.1 笔试真题的作用不是背题而是校准方向很多人复习时喜欢四处找“原题”和“面经”背了一份又一份但遇到稍微变形的题目就懵了。搜狗这场笔试给我的启发是真题真正的价值不是让你背着答案去考场匹配而是告诉你这家公司、这个岗位最看重哪些能力维度。搜狗后端笔试很明显在强调三件事扎实的语言功底、清晰的算法思维、以及处理边界条件时的工程素养。你需要做的是拿一套真题做一次模拟考严格按照线上笔试的规则来计时、不翻资料、代码写进编辑器。考完之后对照答案逐题分析错因把这个过程当成一次“体检”再根据暴露出来的薄弱点安排复习优先级。5.2 算法题练什么Hot 100加剑指Offer足够如果你现在还在海量刷题建议停下来做一个减法。后端校招笔试的算法题难度绝大多数落在LeetCode Hot 100和《剑指Offer》的范围内。字符串处理、栈与队列、二叉树遍历、动态规划、并查集、排序与二分把这些专题吃透比刷500道重复题有意义得多。每道题刷完不要直接进入下一道花5分钟在代码旁边写一行备注比如“这题考双指针慢指针维护左边界快指针负责扩展”。笔试前几天只看这些备注能在很短时间里唤醒每道题的核心思路。5.3 基础八股怎么背能讲出“为什么”才算会校招八股让人头疼但如果只是死记硬背面试官稍微追问一句就会露馅。我当时参考了一个很有效的办法每准备一个知识点就当自己是在给一个刚入门的学弟讲明白把原理、为什么这么设计、有什么缺点、怎么解决全部口述一遍。讲不清楚的地方就是还没掌握的地方。拿“为什么TCP建立连接需要三次握手”举例不能只回答“为了确认双方收发能力”。要能往下说一次握手服务端能确认客户端发送能力二次握手客户端能确认服务端收发能力但服务端还不知道客户端接收能力是否正常所以需要第三次握手。这种递进理解才是真正的掌握。5.4 简历项目怎么准备后端笔试不考项目但面试会挖这场笔试本身没有项目题但在后面的面试环节我从简历上写的“秒杀系统”项目开始被连续追问了数据库索引设计、Redis缓存与数据库一致性、接口幂等性、线上故障排查四个方向。笔试考的是你能不能进门面试考的是你有没有真功夫。所以准备笔试的同时不要丢下项目。至少要把每个项目里的核心模块画一张架构图把请求从入口到数据库的完整路径走一遍想清楚每一步的耗时、并发、容错是怎么处理的。面试官喜欢顺着一条链路往下钻你提前把这条路走通自然能接住问题。如果你也在准备后端校招建议拿这套卷子做一次全真模拟考。做完之后别急着对答案先把每道题按我上面复盘的方式重新过一遍把错因、正确思路、同类题目扩展写下来。我当时正是在这次“翻车”之后把复习重心从刷难题调回了基础巩固和边界训练后面再面其他公司反而轻松了很多。