
小红书2020校招算法笔试题卷一算是当年那批互联网校招卷子里比较有代表性的一套。我当时刷完最深的感受是它没有刻意追求偏题怪题而是在基础算法、数据结构、机器学习理论之间找了一个相对平衡的点。无论你投的是算法岗还是推荐算法岗这套卷子覆盖的考点都值得认真过一遍。今天这篇文章我以参与者和复盘者的视角把卷子里最核心的知识点拆开讲一讲涉及 KMP、排序、贪心、Dijkstra、KNN、聚类这些高频考点同时把我在刷题和真实笔试中踩过的坑一并写出来希望能帮你少走弯路。1. 试卷整体盘点一张卷子里的算法全景图1.1 这份卷子考了什么四类题型的真实分布小红书2020校招算法笔试题卷一整体题型可以分成四类客观选择题、代码编程题、机器学习与深度学习基础题以及少量偏应用的分析题。选择题主要考察数据结构、排序算法复杂度、字符串匹配等基础概念编程题则是典型的算法实现包括贪心、堆、图论最短路和快速幂这类高频考点。机器学习部分集中在 KNN、聚类、损失函数、过拟合处理这些面试官特别爱问的老朋友上。从考点密度来看基础数据结构和经典算法的占比最高大概在五成左右机器学习相关在三成剩下的就是一些综合应用和算法分析题。这一点和很多人对算法笔试“全是 LeetCode”的想象不太一样它更像一张复合型卷子既要你代码能力强也要你理论基础扎实。对准备校招的同学来说这种结构其实是好事因为多数考点都可以通过系统训练快速补齐。1.2 为什么这些考点会出现在算法校招里很多人会问小红书这类内容平台为什么要考 KMP、堆排序和 Dijkstra这背后的逻辑是校招算法笔试承担的不是招“资深算法工程师”的功能而是筛选“算法基础合格、有潜力的人”。像 KMP 这种字符串匹配算法靠记忆也能背下来但真正考察的是你对 next 数组递推关系的理解堆排序和 TopK 问题对应的是海量数据处理中最基础的能力图论最短路对应的是关系链路计算、路径推荐等真实业务场景。再往深一层想内容平台里有大量文本、图片、用户行为数据算法岗入职后接触的第一件事往往是特征工程、排序模型和召回链路。这些工作不直接用到 Dijkstra但需要你有扎实的数据结构和算法底子去处理数据清洗、索引构建、候选集合并等任务。笔试题并不追求面面俱到地模拟业务而是通过经典算法问题看你的计算思维底子这也是这套卷子能成为经典的原因。2. 选择题与基础题那些容易丢分的经典陷阱2.1 KMP算法next数组从手算到代码的必备技能KMP 是算法笔试选择题里的常客这套卷子里也出现了模式串 next 数组计算的考察。题目大意是对于模式串 p写出它的 next 数组。这里我们按最常见的定义来讨论next[i] 表示 p 中从头开始长度为 i 的子串的最长相同真前后缀长度其中 next[0] 根据教材约定可能取 -1 或 0笔试时一定要先看清题目给出的定义再动手。以字符串 p abacaba 为例我完整手算一遍。next[0] 按约定取 -1i 1 时看子串 a真前后缀为空长度为 0i 2 时看 ab没有相等前后缀长度为 0i 3 时看 aba最长相等前后缀是 a长度为 1i 4 时看 abac没有相等前后缀长度为 0i 5 时看 abaca最长相等前后缀是 a长度为 1i 6 时看 abacab最长相等前后缀是 ab长度为 2i 7 时看 abacaba最长相等前后缀是 aba长度为 3。所以对应的 next 数组是 [-1, 0, 0, 1, 0, 1, 2, 3]。我的经验是遇到这类题第一件事不是急着算而是把题目给出的 next 定义读三遍。有的题目里 next[i] 定义为“第 i 个字符匹配失败后回退的下标”那得到的结果会和上面的数组有差异。很多丢分不是不会算而是定义没看清。2.2 排序算法的复杂度与稳定性速查排序算法是选择题里的“送分题”但也最容易因为记忆混淆丢分。我把高频排序算法整理成了一张速查表考前值得反复默写算法平均时间复杂度最坏时间复杂度空间复杂度稳定性冒泡排序O(n²)O(n²)O(1)稳定插入排序O(n²)O(n²)O(1)稳定选择排序O(n²)O(n²)O(1)不稳定快速排序O(n log n)O(n²)O(log n)不稳定堆排序O(n log n)O(n log n)O(1)不稳定归并排序O(n log n)O(n log n)O(n)稳定计数排序O(n k)O(n k)O(k)稳定这张表要记牢因为选择题很少只问时间复杂度往往会把稳定性、最坏情况、空间开销混在一起设陷阱。比如快速排序在数组已经有序时会退化成 O(n²)堆排序最坏情况也是 O(n log n) 但是不稳定归并排序稳定但需要额外 O(n) 空间。我当年就因为在“堆排序是否稳定”这个问题上栽过一次后来每次复习排序都先背稳定性结论稳定的有冒泡、插入、归并、计数和基数简单选择、快排、堆排都不稳定。2.3 数据结构细节堆、栈、字典的实际作用选择题里还会穿插一些数据结构细节比如堆的插入和删除复杂度、栈的弹出顺序、哈希表的扩容机制等。常见的有向大小为 n 的堆中插入一个元素需要 O(log n) 时间删除堆顶也是 O(log n)但建堆有两种方式将 n 个元素逐个插入的复杂度是 O(n log n)而用数组自底向上建堆则是 O(n)。这个问题很容易被忽略因为大家平时直接用现成的优先队列很少关心底层实现。哈希表相关题目则常常考察冲突处理和负载因子。开放寻址法和链地址法各有适用场景负载因子越大冲突概率越高扩容也就越频繁。很多编程语言的标准库默认负载因子在 0.75 左右扩容时容量翻倍。这些细节虽然不起眼但在选择题里的出现频率很高。备考时一定要把常用数据结构的底层实现过一遍而不是只停留在 API 使用层面。3. 核心编程题解析从贪心到图论的实战思路3.1 经典贪心题区间类问题的通用解法编程题第一道通常不会太难常见的是区间调度或任务安排类题目。比如给一组区间求最多能选出多少个互不重叠的区间这类问题用贪心很好解决先按区间右端点排序再依次选择不冲突的区间加入结果集。排序的目的是为了让每个已选区间尽量早结束从而为后面的区间留出更多空间。这类题要拿满分关键在于两点。一是能说清楚为什么“按右端点排序”比按左端点或区间长度排序更优。二是代码实现时注意边界条件比如区间相交的判断是next_start current_end还是取决于题目定义的是开区间还是闭区间。我见过不少候选人因为边界处理差了一个等号被卡样例。实际笔试时我会先把题目的输入输出格式看清楚再用小数据手推一遍结果避免代码写完后才发现理解偏差。3.2 堆排序与TopK问题从手写堆到快速选择TopK 问题是算法笔试的另一个高频题也是这套卷子里的重头戏。最直接的思路是把所有元素放进一个大小为 k 的小根堆遍历过程中如果当前元素比堆顶大就弹出堆顶再插入当前元素最后堆里留下的就是最大的 k 个元素。用 Python 可以借heapq模块快速实现但面试官很可能要求你手写堆的操作所以向下调整和向上调整这两个过程一定要练熟。如果数据规模特别大内存中放不下全部数据那就需要换思路一种是用分治思想配合归并另一种是使用快速选择算法。快速选择的平均复杂度是 O(n)比建堆 O(n log k) 更快但它会改变原数组顺序且最坏情况下也是 O(n²)。笔试时如果不要求写出最优解法我通常建议先用最容易写对的解法拿分有时间再优化这样至少能保证部分评测用例通过比直接空着强得多。3.3 Dijkstra单源最短路手写模板与边界图论最短路是这套卷子里比较“硬核”的编程题。Dijkstra 算法的核心是贪心加动态规划每次从未确定最短距离的节点中取出距离最小的节点 u然后尝试用 u 去松弛它的所有邻居。要注意的是Dijkstra 只适用于边权非负的图如果题目里出现负权边就要改用 Bellman-Ford 或 SPFA。我用 Python 写一个堆优化的标准模板笔试时可以参照这段结构import heapq def dijkstra(n, edges, start): graph [[] for _ in range(n)] for u, v, w in edges: graph[u].append((v, w)) graph[v].append((u, w)) # 无向图加这条有向图不加 dist [float(inf)] * n dist[start] 0 pq [(0, start)] while pq: d, u heapq.heappop(pq) if d dist[u]: continue # 这个节点已经被更优路径更新过跳过 for v, w in graph[u]: nd d w if nd dist[v]: dist[v] nd heapq.heappush(pq, (nd, v)) return dist这个模板里最关键的一行是if d dist[u]: continue也就是堆优化里的“懒删除”策略。因为堆中可能残留旧距离的节点弹出后如果发现当前距离已经大于记录的最短距离说明这个节点已经通过其他路径被更新过了直接跳过即可。很多新手第一次写 Dijkstra 时忘了这个判断导致结果错误甚至死循环。另外注意节点编号是 0 开始还是 1 开始笔试时输入输出格式不同数组下标很容易差一这属于回头检查时最容易发现的低级错误。4. 机器学习与深度学习考点算法岗笔试的另一面4.1 KNN与聚类基础算法的原理与细节这套卷子里的机器学习题整体难度不高但非常注重细节。比如 KNN多数人都知道它是基于距离的惰性学习算法但题目真正想问的往往是如何选择 K、使用什么距离度量、特征需不需要归一化。K 选太大会让决策边界过于平滑K 选太小则容易受噪声影响交叉验证是确定 K 的常用手段。距离度量方面欧氏距离、曼哈顿距离、余弦相似度适用于不同场景文本向量用余弦相似度往往比欧氏距离更合理。特征归一化这一点也容易丢分如果各特征量纲差异大欧氏距离会完全被量纲大的特征主导所以要先做标准化或归一化。聚类算法的考察重点则是 KMeans。笔试常问的两个问题是如何确定 K 值KMeans 一定会收敛吗K 值可以用肘部法则结合轮廓系数判断也可以直接用业务经验确定。KMeans 的目标函数是每个样本到其所属簇中心的距离平方和算法通过交替更新簇分配和簇中心来最小化这个目标函数理论上它保证收敛到局部最优但不保证全局最优。所以面试题里如果问“不同初始中心是否影响结果”答案是肯定的实际工程中常通过多次随机初始化加 k-means 来缓解这个问题。4.2 损失函数、梯度下降与过拟合机器学习理论题里损失函数和优化方法是必考项。回归任务常用均方误差分类任务常用交叉熵。要理解为什么分类不用 MSE是因为 softmax 加交叉熵的梯度形式更简洁均方误差在概率输出上容易导致梯度消失的问题。梯度下降相关的考点集中在三种形态上批量梯度下降、随机梯度下降和小批量梯度下降。三者核心区别在于每次更新使用的样本数量批量梯度下降稳定但计算量大随机梯度下降每步只用一个样本所以震荡大但能跳出局部最优小批量则是两者之间的折中。过拟合的应对方法也是高频考点可以从数据、模型、训练策略三个层面回答。数据层面可以做数据增强、收集更多样本模型层面可以加正则化、简化网络结构、用 dropout训练策略层面可以早停、降低模型容量。注意答题时不能只列方法名最好能简要说明原理比如 L2 正则化为什么能抑制过拟合是因为它在损失函数中加入了权重平方和梯度下降时相当于每次都对权重做衰减让模型倾向选择更小的参数从而降低模型复杂度。4.3 卡尔曼滤波与粒子群等进阶算法的考察方式这套卷子里还出现了一些偏进阶的算法概念比如卡尔曼滤波、模拟退火、粒子群算法。它们通常以选择题或简答题形式出现考察的是原理理解而非手写实现。卡尔曼滤波的核心思想是“预测 更新”两阶段递推它假设系统噪声和观测噪声都服从高斯分布通过融合预测值和观测值得到最优估计。模拟退火算法则是模拟金属退火过程用温度控制接受较差解的概率温度越高越容易接受差解从而跳出局部最优。粒子群算法PSO更是经常被问到的智能优化算法它模拟鸟群觅食行为。每个粒子有位置和速度两个属性迭代时通过个体历史最优 pbest 和群体历史最优 gbest 来更新速度再更新位置。速度更新公式里有两个关键参数 c1 和 c2分别控制向个体最优和全局最优学习的程度另外还有惯性权重 w用来平衡探索和开发能力。笔试如果考到这类题目通常不会让你写完整算法而是考你对公式的理解比如问“w 过大或过小时算法的搜索行为会怎样”记住结论就能拿分w 过大粒子飞行速度变化不明显全局探索能力强但收敛慢。w 过小粒子容易被群体最优吸引收敛快但容易陷入局部最优。c1、c2 设置不当也会导致粒子震荡或提前收敛通常取相等值即可。5. 写代码的坑与提分技巧复盘真实的笔试现场5.1 输入输出处理的三个常见坑算法笔试的编程题代码思路对了也可能因为输入输出处理不当而大面积失分。第一个坑是不知道输入有多少组。题目常写“输入包含多组测试数据”但在线评测系统有时一行就是一组有时连续多行是一组必须先按行读取再判断结束条件。第二个坑是 Python 的input()和sys.stdin.readline()混用导致读取出错建议全程用sys.stdin配合split()解析。第三个坑是输出格式比如“每个结果占一行”或者“结果之间用空格分隔”多了一个空格或换行都可能导致答案错误。我个人的习惯是写代码前先构造一个小的输入样例手算出期望输出再运行代码比对。这个过程只需要一分钟但能避免大量低级错误。编程题不像 LeetCode 那样已经封装好输入输出笔试平台的接口更原始平时练习时不要只在 LeetCode 上刷题建议每周至少用在线笔试系统练一次提前适应输入输出手写的环境。5.2 暴力解法先拿分再逐步优化很多同学上了笔试平台就容易陷入一种误区只写最优解写不出来就卡死在一道题上。我的建议恰恰相反任何题目都先评估一下能不能用暴力解法拿到部分分。比如一张卷子有 5 道编程题第一道可能 10 个测试点暴力解法能过其中 6 个优化解法能过全部 10 个那最优策略肯定是先快速把 6 个测试点拿到手再做后续题目最后有时间再回头优化。之所以强调这个策略是因为校招笔试的判分通常是按通过的测试点数量来算的而不是只看有没有 AC。哪怕 O(n²) 的解法在大数据量时超时小数据量也能拿分。我见过很多候选人因为执着于写最优解结果最简单的题都没提交成功。合理的时间分配应该是每道题先用 10 分钟想出最直接的解法并写出来如果剩余时间充足再考虑优化而不是一上来就死磕最优方案。5.3 时间复杂度的估算能力如何快速判断代码能否跑过在线评测平台通常会有明确的时间限制比如 1 秒或 2 秒C 在 1 秒内大概能执行 10^8 次基础运算Python 则会慢一个数量级大概只有 10^7 左右。这个估算能力在笔试中非常关键因为你写代码前就应该预判自己选的算法是否能在时限内通过。比如数据规模是 10^5O(n²) 就是 10^10 次运算Python 绝对跑不完必须换 O(n log n) 或 O(n) 的解法。我看到过一个非常好的习惯拿到每道题先看数据范围再决定算法。n 小于等于 20 可以考虑状态压缩或暴力搜索n 小于等于 500 可以用 O(n³) 的 Floyd 或区间 DPn 小于等于 10^5 就需要 O(n log n) 甚至 O(n)n 到达 10^7 以上则基本只能考虑 O(n) 或更优算法。这套估算方法可以帮你快速排除掉不合适的思路避免在错误解法的路上浪费太多时间。6. 从笔试到面试算法题准备的长期建议6.1 刷题策略按专题训练比盲目刷题更有效关于校招算法准备我最想分享的一点是按专题刷题远比按题目顺序刷题更高效。这套卷子本身就体现了专题化的特点链表、二叉树、排序、贪心、动态规划、图论各占一块。如果你今天做一道链表题明天做一道动态规划大脑很难形成系统的解题框架。更好的方式是用两周时间把某个专题吃透比如这周只做二叉树的遍历、最近公共祖先、序列化反序列化下周再做动态规划的背包类、区间类、序列类问题。每个专题里要把高频套路总结成模板。比如二叉树题大多基于递归动态规划题先要定义状态再写转移方程链表题经常会用到快慢指针和虚拟头节点。我备考时建了一个自己的算法笔记每个专题一页记录经典题目、模板代码、复杂度分析和易错点考前翻一遍比临时刷几十道题都有用。校招笔试题型再变核心套路就那些只要专题训练足够扎实考场上遇到新题也能快速归到已知框架里。6.2 现场手撕代码的注意事项进入面试环节以后手撕代码的场景会暴露更多问题而这些问题往往从笔试阶段就开始养成了。首先是写代码前要跟面试官确认清楚需求比如输入是否可能为空、数组元素是否有负数、目标是最大还是最小这些边界条件直接影响代码正确性。其次是写完代码后一定要主动跑一个简单例子把循环和递归的过程在脑子里走一遍这一步能发现绝大多数粗心错误。还有一个容易被忽略的点不要把题目解完就结束要做复杂度分析并思考还能不能继续优化。面试官让你做 TopK你用堆实现了如果补充一句“数据量特别大时可以用分布式的思路拆分到多机处理”这就是加分项。笔试虽然看不到这种互动但平时养成这种思考习惯能让你在考场上写代码时更注重代码结构和边界处理而不是只顾着套模板。我一直觉得算法笔试的本质不是比谁见过的题多而是比谁的基础更扎实、临场更稳定。小红书2020校招算法笔试题卷一的很多考点放到现在依然是校招笔试的主流方向从 KMP 到排序从贪心到图论从 KNN 到过拟合每一块都值得反复练、反复梳理。备考这件事没有太多捷径按专题一步步啃下来多总结自己的易错点考场上正常发挥就已经能超过绝大多数人了。最后再分享一个小技巧做套题的时候一定要严格计时模拟真实笔试的紧张感因为很多人在平时刷题时能 AC一限时就容易心态失衡这一点越早适应越好。