2020年8月8日周六下午两点半我参加了网易算法岗的在线笔试。印象很深因为那天很热房间里空调嗡嗡响我在等待笔试平台加载的时候手心全是汗。现在回头看这次笔试暴露了不少我在准备阶段忽略的问题也让我后续刷题更有方向。这篇复盘从题型分布、选择题考点、编程题思路到考场时间分配全部整理成文字给准备算法岗笔试的朋友做一个参考。网易算法岗笔试复盘不只是把题目回忆一遍那么简单。它更像一次体检能让你看清自己的基础扎不扎实、代码手写熟不熟练、遇到陌生题的心态稳不稳。这篇文章适合正在投算法岗实习或校招的同学也适合那些刷题刷到一定量但还没做过在线笔试的人。1. 笔试整体情况与时间分配1.1 题型分布与算法岗考察侧重点网易算法岗的笔试和开发岗有明显区别。开发岗大量考察数据结构、操作系统、网络协议算法岗则更偏机器学习基础、概率统计和代码实现能力。我当时考的内容大致分为两部分选择题和编程题。选择题二十道左右覆盖机器学习、深度学习、概率论、线性代数编程题三道难度从简单到中等递进没有特别偏的竞赛题但也不是纯模板题每道都带一点变体。算法岗笔试的核心逻辑是先看你的理论基础再看你能否把理论落到代码里。选择题不是送分题很多概念不能只记结论得理解推导过程。比如问L1正则和L2正则的区别如果只背了“L1稀疏、L2平滑”这种话换个角度问你为什么L1能产生稀疏解就很容易卡住。后面的编程题更像是对编码基本功的检验三道题都是在常见模型上做了一点改动如果你只是背过模板变体一来就露馅了。1.2 时间分配方案两小时怎么花最值网易这场笔试题量不算少两小时其实挺紧张。我当时的策略是先快速做完选择题能确定的直接选有两个选项拿不准的就先标记跳过不在一道题上死磕。选择题我控制在三十分钟到四十分钟之间剩下的时间全部留给编程题。编程题建议按从前到后的顺序做但不要平均分配时间。第一题通常最简单花十五分钟以内搞定第二题是中等难度给足四十分钟第三题如果一时没思路先写暴力解拿部分分再考虑优化。我见过不少同学在第三题上死磕结果第二题没写完得不偿失。编程题最后留十到十五分钟统一检查边界条件、输入输出格式和变量命名问题。这里有一个实用的细节在线笔试系统通常不支持本地编译调试所以手写代码时更要注意缩进和语法。如果你平时习惯用IDE的自动补全考前一定要在纯文本编辑器里多练几次不然真到考场上光是一个括号匹配问题就能浪费五分钟。2. 选择题复盘机器学习与概率统计的那些坑2.1 卷积尺寸计算与感受野选择题里出现了一道卷积输出尺寸计算的题这种题属于“看一眼就知道考什么”的类型但仍然有细节陷阱。公式是输出大小 (输入大小 - 卷积核大小 2 * padding) / stride 1。看着简单可一旦padding或者stride不是常规值就容易算错。我当时碰到的情况是一个32×32的输入卷积核5×5stride为1padding为2问输出特征图的尺寸。代入公式就是(32 - 5 4)/1 1这里先算分子32 - 5 4 31除以1加1后等于32。所以输出还是32×32尺寸不变。关键是必须检查括号内能不能被stride整除如果不能整除很多框架会向下取整这时候计算结果就和你想的不一样了。还有一道题考察感受野的计算。感受野是卷积神经网络里一个高频考点公式是第n层感受野 (第n-1层感受野 - 1) * stride_n kernel_n从后往前推。很多人记反公式或者把全局步长当成当前层步长导致计算结果差很多。实际上推感受野最稳定的方式是一层一层从输出往输入推别想着用全局公式一步算出最终值手动推两层你就能发现中间层感受野的变化趋势反而不容易出错。2.2 概率题条件概率与贝叶斯公式的考场变形概率统计也是算法岗笔试的常客。有一道题考察贝叶斯公式大致场景是某人做一次检测阳性结果并不代表一定患病因为检测存在假阳性率和假阴性率问已知检测结果阳性的条件下真实患病的概率是多少。这类题核心是分清P(患病|阳性)和P(阳性|患病)的区别。设患病率为0.01检测灵敏度真阳性率是0.99特异度真阴性率是0.95那么P(患病|阳性) 0.01 * 0.99 / (0.01 * 0.99 0.99 * 0.05)算出来大概只有0.167。很多人一看到99%的准确率就觉得概率接近1实际上由于患病率极低即使检测阳性真患病的概率也很小。这个题深刻反映了贝叶斯公式中先验概率对后验概率的影响笔试考它不是为了难为你而是想看你有没有真正理解条件概率和“基准率谬误”。概率题给我们的备考启示是不要把重心完全压在代码刷题上。算法岗的笔试选择题会直接考察这类数学基础尤其贝叶斯公式、期望、方差、最大似然估计这些高频考点最好自己推一遍别只看结论。2.3 损失函数与正则化易错点还有几道选择题和个人经验关系很大一道关于交叉熵损失和二分类问题一道关于L1正则化。题目问的是当使用交叉熵损失训练二分类模型输出经过sigmoid后梯度更新时会不会出现梯度消失。这里的关键在于交叉熵和sigmoid的组合梯度形式会简化成预测值与真实值之差并不会出现sigmoid函数在饱和区梯度趋近于0的情况。这就是为什么分类任务常用交叉熵而不是均方误差的重要原因MSE加sigmoid在输出接近0或1时梯度会非常小导致收敛极慢。L1正则的题问的是“为什么L1正则能产生稀疏解”。这个要从优化角度看L1正则的约束区域是菱形L2是圆形目标函数等值线和菱形相交时更容易落在坐标轴上所以某些维度的权值会被压到0。如果你只是背了结论选对是运气换成让你判断“L1是否更适合特征选择”时还是会懵。这类选择题的价值在于提醒我们机器学习基础不能只看面经要理解原理背后的数学逻辑。算法岗笔试喜欢在常见知识点上“多问一步”这一步就是拉开差距的地方。3. 编程题实战从审题到AC的全过程拆解3.1 题目一合并区间贪心与排序第一道编程题是一个合并区间的变体和经典的“合并重叠区间”几乎一样只是输入不是二维数组而是一个由区间对象组成的列表每个区间有start和end两个属性要求返回合并后的区间个数。题目本质上考察排序和贪心。解决思路是先按区间起点升序排序如果起点相同则按终点升序然后依次遍历维护当前合并区间的右端点。如果下一个区间起点小于等于当前右端点说明有重叠更新右端点否则直接开启一个新区间。我写的第一版代码就是这样def merge_intervals(intervals): if not intervals: return 0 intervals.sort(keylambda x: (x.start, x.end)) merged [intervals[0]] for item in intervals[1:]: if item.start merged[-1].end: merged[-1].end max(merged[-1].end, item.end) else: merged.append(item) return len(merged)这里有个隐藏坑item.start merged[-1].end这个判断里等于的情况是算重叠的例如区间[1,3]和[3,5]按题目要求是要合并成[1,5]。如果你写成严格小于号就会漏掉这种边界情况。这道题我花了大概十二分钟写完后又特地检查了空数组输入和单区间输入。这两种情况容易被忽略但往往就是题目设置的范例陷阱。3.2 题目二带障碍物的路径规划动态规划第二题是动态规划考察的是“不同路径”的带障碍版本。题目大意是一个m行n列的网格用0表示空地、1表示障碍物机器人从左上角走到右下角每次只能向下或向右移动问有多少条不同路径。动态规划的状态转移其实很清晰dp[i][j] 表示走到第 i 行第 j 列的路径数。在没有障碍的情况下dp[i][j] dp[i-1][j] dp[i][j-1]分别对应从上边和左边过来。有了障碍物只要把障碍物位置的dp值置0即可。我写的时候用的是二维dpdef uniquePathsWithObstacles(obstacleGrid): if not obstacleGrid or not obstacleGrid[0]: return 0 m, n len(obstacleGrid), len(obstacleGrid[0]) dp [[0] * n for _ in range(m)] if obstacleGrid[0][0] 0: dp[0][0] 1 for i in range(m): for j in range(n): if obstacleGrid[i][j] 1: continue if i 0: dp[i][j] dp[i-1][j] if j 0: dp[i][j] dp[i][j-1] return dp[-1][-1]这里有一个初学很容易犯的错初始化第一行和第一列时如果中间出现障碍物后面所有格子都走不到值应该直接置0不能只把障碍物位置设为0就完事。用二维dp循环的方式天然规避了这个问题因为当前格子的值完全由上方和左方递推而来一旦前一个格子是0后面的结果自然就是0。空间上其实可以优化成一维数组用一维数组时要注意遇到障碍物时要把它对应的dp位置为0而不是像空地那样直接累加。我当时为了求稳直接用二维dp毕竟在线笔试环境下能AC就行空间优化属于锦上添花不必铤而走险。实际写代码时我用了大概二十分钟大部分时间花在检查障碍物初始化的逻辑上。3.3 题目三完全二叉树判断BFS与状态设计第三题是一棵二叉树的判断问题要求判断给定二叉树是否为完全二叉树。完全二叉树的定义是除了最后一层外每一层都是满的最后一层的节点都靠左排列。判断完全二叉树的经典解法是用层序遍历借助一个布尔标记记录是否已经出现过空节点。具体思路是按层顺序逐节点入队如果当前节点是空节点说明之后的节点不能再是非空节点如果出现了“空节点之后还有非空节点”的情况则不是完全二叉树。我当时的代码from collections import deque def is_complete_tree(root): if not root: return True q deque([root]) seen_null False while q: node q.popleft() if node is None: seen_null True continue if seen_null: return False q.append(node.left) q.append(node.right) return True这个解法的关键点在于层序遍历的时候要把空节点也入队然后用 seen_null 标记是否已经遇到过空节点。如果某个非空节点是在空节点之后出现的说明层序序列中间缺了一块不是完全二叉树。我一开始写的版本忘了把空节点入队结果判断结果是错误的。因为如果不入队空节点BFS碰到None就直接跳过无法区分“最后一层缺少左孩子”和“左孩子是空但右孩子存在”的情况。调试时用一组反例就能测出来比如根节点只有右孩子没有左孩子如果空节点不入队它会直接遍历右孩子最终错误地返回True。这道题有点意思因为它表面是BFS实际考察的是对层序序列完整性的理解属于那种“思路一听就懂代码一写就错”的题目。3.4 考场上的时间与精力分配细节三道编程题做完我大概还剩十分钟。整个过程里有一个很值得说的细节第二题我一开始想到的是递归搜索写完发现复杂度太高直接改成动态规划。其实在笔试中第一版思路如果发现实现越来越复杂就要立刻停下来重新想不要抱着“写着写着可能就对了”的心态硬刚。还有一个细节是读题。第三题的题目描述里有一句提示“完全二叉树的层序遍历序列中不会出现非空节点出现在空节点之后的情况。”这句话对理解题意非常有帮助但如果你做选择题做太久压缩了编程题时间很容易在紧张状态下忽略这类提示。所以我建议在线笔试时选择题绝不要恋战快速解决把心理带宽留给孩子一样的代码题。代码提交前要检查的点包括变量名拼写、Python中is和的区别判断None时用is、列表索引是否越界、是否有中英文括号混用。这些低级错误平时在IDE里不会被放大但在在线编辑器里只要你手一抖可能连编译都过不了。4. 常见问题与排查技巧实录4.1 环境与输入输出的老坑在线笔试最常见的坑不是题目本身而是输入输出。网易笔试平台支持自己选择编程语言我当时选了Python。很多同学会卡在输入解析上比如输入给的是矩阵但每一行的元素用空格分隔行与行之间可能有空行直接用input()读反而容易出错。我的建议是在笔试前熟悉你所用语言的快速输入写法。Python里可以用sys.stdin.read().split()把整个输入一次性读进来再按索引解析处理多行矩阵时比逐行input()更稳还能避免行尾多余空格的干扰。输出格式一定要严格匹配题目要求不要多打印提示文字。程序运行时所有print都会被当成答案的一部分多打一句“请输入”直接判错。还有一种情况是本地运行正常提交后答案错误。很可能是你没有考虑多组测试用例有些题会包含多组输入你要用循环去处理而不是只读一次。我当时第一道合并区间的题就没考虑多组输入问题所幸题目明确写了单组输入不然肯定翻车。4.2 卡题时的三种自救姿势第二道动态规划题我中途卡了一下想确认dp数组的初始值写法。这里分享一下我化解卡壳的三种方式亲测有效。第一种回到题目示例手动推演。比如路径题你拿一个2×2的小矩阵自己手动算一遍看看dp值应该是什么再反推状态转移方程有没有问题。这比盯着屏幕发呆高效得多。第二种写一个最暴力的解法先把基础分拿到。哪怕复杂度很高只要答案正确就能拿到部分测试用例的分数。有的同学一上来就追求最优解反而容易把自己卡死在优化环节。第三种调整做题顺序。如果第三题十分钟内一点思路都没有立刻回头检查前两题的边界情况确保已经拿到的分数不会丢。笔试是拿分游戏不是竞赛排行榜把能拿的分拿稳比解出最难的题更重要。4.3 交卷前的检查清单交卷前的十五分钟我习惯按以下清单过一遍代码这份清单也是我从无数场笔试中总结出来的。首先是数组越界检查尤其是循环里用了len()的地方。其次是整数溢出C选手可能要考虑long longPython虽然不会溢出但要注意大数运算的时间开销。然后是空输入、单元素输入、全0输入、全1输入等边界情况能构造的用例都构造一下。最后是变量名是否和题目关键词一致有些平台会对主类、主函数有要求比如Java要求类名是Main如果不按要求命名直接编译报错。我见过一个朋友参加笔试时因为方法名拼错编译器报错后找了五分钟才找到问题。这种低级错误是真的可惜。交卷前把每一题的输出用题目给的样例跑一遍这是最基本的要求花不了几分钟但能救回不少分。4.4 两小时笔试的实际节奏记录复盘一下我当时的时间线选择题花了三十五分钟很多基础题一眼出结果有两道概率题犹豫了一下第一道编程题十二分钟完成第二道编程题二十分钟完成第三道编程题写写改改花了四十分钟最后八分钟统一检查。整体节奏还算稳但回头看选择题如果再快五分钟第三道题就能更从容地测试边界用例而不是卡在“为什么这个用例没过”的惶恐里。在线笔试的节奏和平时刷题完全不同。刷LeetCode时你有一小时、两小时慢慢琢磨但笔试不一样每题留给你的时间可能只有二十到三十分钟。平时练习就应该给自己限时模拟真实考场环境这样上考场后时间感知会准很多。5. 考后复盘与后续准备建议5.1 复盘的正确姿势趁热打铁笔试结束后我当天晚上就趁记忆还热把三道编程题重新实现了一遍并记录下每道题的卡点。很多人笔试完就彻底放松其实考后两小时内的记忆力是最宝贵的。你还能记起来哪道题你犹豫了很久、为什么犹豫、最后选了什么答案这些东西只要你睡一觉再想回忆就只能是模糊的“大概考了动态规划”。我的复盘方式是建一个表格每一行记录一道题题目类型、用了什么算法、考场上的实现时间、卡点、正确解法的关键点。这张表里积累十几场笔试题之后你会发现自己的薄弱环节特别清晰比如“二叉树题目正确率低”“DP状态定义总是慢”然后有针对性的补强。5.2 薄弱环节补强计划复盘完网易这场笔试我的薄弱环节暴露得很明显概率题和动态规划的空间优化。概率题我后来专门把贝叶斯公式、全概率公式、期望线性性质这一类高频考点重新推了一遍。动态规划则是刷了大量不同状态的题目包括路径类、序列类、背包类每天坚持两道每道题都写状态定义、状态转移和复杂度分析。补强计划还要配合模块化刷题。比如这周专门练“区间类贪心”下周练“二叉树BFS”再下周练“状态压缩”。只刷题不总结等于白刷每道题至少要能回答这个思路为什么对有没有什么边界情况容易漏如果我把题目条件改一下还能不能用同样的思路5.3 从笔试到面试的衔接经验网易这场笔试之后我陆续还参加了其他几家公司的算法岗笔试最后也进入到了面试环节。回头看笔试的很多知识点在面试里都会继续出现比如交叉熵、贝叶斯、动态规划只不过形式从选择题变成现场手撕代码或口头提问。所以每一次笔试都不要只是应付认真复盘就是在为面试攒弹药。我在面试中被问到过“如何处理训练数据中的样本不平衡”其实这背后的原理和笔试中L1正则的选项是同一套逻辑系统。笔试筛的是基础面试筛的是深度两步之间是平滑过渡的你笔试时整理过的每一条笔记后面都可能成为面试时的答题素材。最后再分享一个我个人的小习惯每次笔试结束后我会把最后检查清单贴在自己桌面上下一次笔试前五分钟看一遍。到后面这些检查项逐渐变成肌肉记忆交卷前的恐慌感也就淡了很多。笔试这件事本质上考的不是天赋而是熟练度和稳定的心态复盘一次就长一次经验多做几次你慢慢就摸清那些大厂套路了。