一套校招机器学习笔试题,到底在考什么
每年秋招春招,算法岗的笔试题总是能刷一波存在感。特别是像iHandy这种出海工具类厂商,它的2019校招机器学习/算法工程师笔试题,放在今天看依然有很强的参考价值。原因很简单:这套题覆盖的面非常典型,从数据结构基础到机器学习理论,从经典算法到实际业务场景,基本把校招算法岗笔试该考的东西都串了一遍。我自己在带新人和做技术面试时,也经常拿类似的题目做范本。
这套题适合谁?两类人。第一类是正在准备校招或实习面试的在校生,需要快速摸清算法岗笔试的考点边界和出题风格;第二类是已经工作但想查漏补缺的工程师,可以用这套题自测一下基础是否扎实。这篇文章我会从出题人的视角拆解这套笔试题,分析每个考点背后的真实意图,并结合实际面试场景聊聊备考策略。文章不提供标准答案,但会给你一套完整的解题思路和复习路径。
1. 笔试题整体画像:题型结构、考察范围与难度梯度
先给这套题画个像。iHandy的这套笔试题总体分为三大块:基础算法与数据结构、机器学习理论基础、综合编程题。题型以选择题、简答题和在线编程题为主,整体难度属于中规中矩的校招水平,但其中几道题想要拿满分并不容易。
1.1 题型分布与分值逻辑
从整体结构来看,这套笔试题的设计思路很清晰:先用选择题筛基础,再用简答题看深度,最后用编程题检验动手能力。三个环节层层递进,对应的是算法工程师日常工作中最核心的三种能力:知识储备、理解深度和工程实现。
选择题部分覆盖了排序算法、KMP算法、二叉树遍历、哈希表冲突处理等经典考点,这些题目考察的是“你有没有系统地学过数据结构”。说实话,这类题目靠刷题确实能练出来,但如果你只是死记硬背结论而不理解原理,稍微换一个问法就容易翻车。比如排序算法的稳定性,很多人背了“快排不稳定、归并稳定”的结论,但一旦问“为什么快排不稳定”就卡住了。
简答题部分则聚焦机器学习的核心概念,包括模型评估指标、过拟合与欠拟合、常见算法的原理与适用场景等。这部分考察的是“你是否真正理解模型背后的机理”,而不仅仅是会调用sklearn的API。我记得有一道题问的是“如何解决样本类别不平衡问题”,这个问题在实际业务中太常见了,如果只答“用SMOTE过采样”而不展开说明过采样可能带来的过拟合风险,分数肯定拿不全。
编程题通常会有两到三道,难度从二叉树遍历到动态规划不等,考察的是扎实的编码能力和算法设计能力。这部分是区分度最高的,因为选择题和简答题可以通过短期记忆突击,但编程题必须在有限时间内写出能AC的代码,没有真功夫是过不去的。
1.2 难度梯度设计:从送分题到筛选题
这套题的难度梯度设计得很讲究,基本遵循“532原则”:50%基础题,30%中等题,20%拔高题。
基础题的目标是快速淘汰没有系统准备过的候选人。比如“冒泡排序的时间复杂度是多少”“哈希表的平均查找时间复杂度是多少”这类题,只要上过数据结构课或者刷过LeetCode热题,基本都能答对。这类题没什么好说的,靠的就是平时积累。
中等题开始考察知识的深度和灵活性。比如KMP算法的next数组计算、动态规划的状态转移方程设计,这些题目要求你不仅知道算法长什么样,还要理解它为什么这样设计。拿KMP来说,很多人能背出next数组的求解代码,但问他“为什么next[0]要初始化为-1,next[1]通常为0”,能答清楚的人就少了一半。
拔高题则考察综合能力和临场反应。比如给你一个业务场景,要求设计一个推荐排序策略或者文本分类方案,这种题目没有标准答案,考察的是你能否把学过的知识灵活运用。我见过不少候选人笔试成绩很高,但一到这种开放性问题就露馅了,答案东拼西凑、缺乏逻辑主线。
1.3 这套题的核心信号:公司想要什么样的算法工程师
从这套笔试题的选材和风格,我们能读出iHandy这类公司对算法工程师的核心期待:理论基础扎实、代码能力过硬、业务理解到位。这三者缺一不可。
很多在校生有一个误区,觉得算法工程师就是天天调参、跑模型,数据结构与算法这种“底层知识”不重要。但实际工作中,你处理海量数据时写的每一个数据处理脚本、设计每一个特征工程流程、优化每一段模型推理代码,都在考验你的算法基本功。一个排序算法都写不利索的人,很难让人相信他能写出高效的数据处理管道。
另一个信号是:公司非常看重候选人对机器学习基础概念的理解深度。不是让你背出SVM的公式推导,而是要求你能解释清楚“为什么SVM对异常值敏感”“逻辑回归为什么要用交叉熵作为损失函数”这类问题。能回答这类问题,说明你是真的理解而不是只会调包。
2. 数据结构与经典算法:笔试中的“兵家必争之地”
数据结构与算法在算法岗笔试中的权重非常高,因为这是最客观、最容易量化评估的部分。代码能不能跑通、时间复杂度够不够优,一目了然,没有模糊地带。
2.1 排序算法:不只是背复杂度表
排序算法是笔试题中的常客,iHandy这套题也未能免俗,考察了冒泡排序、快速排序、堆排序等经典算法。很多同学觉得这部分太基础,不值得花时间复习,但实际面试中,排序算法的考察从来不只是“背出时间复杂度”。
比如面试官可能会问:“快速排序在最坏情况下的时间复杂度是多少?如何避免?”如果你只回答“O(n²),用随机选pivot可以避免”,这只是及格水平。更好的回答应该包含:快速排序的性能退化原因是每次分区极度不均匀,随机选pivot或三数取中法可以让退化概率降到极低,甚至可以从概率上证明期望时间复杂度是O(n log n)。
再比如稳定性问题。笔试中常考“以下哪个排序算法是稳定的”,但实际工作中你大概率会遇到“我需要按多个字段排序,如何保证不破坏上一次排序结果”这类真实需求。这时候归并排序的稳定性就有用了,或者你可以用“先按次要字段排序,再按主要字段排序”的方式,配合Python的sort函数(基于Timsort,稳定排序),优雅地解决问题。
还有一个细节值得注意:堆排序虽然时间复杂度是O(n log n),但由于其缓存不友好的特性,实际运行速度往往不如快排。笔试中如果要你实现堆排序,考察重点通常是你是否理解“下沉”和“上浮”操作,以及如何用数组表示完全二叉树。这个知识点写代码容易,理解透彻难。
2.2 KMP算法与next数组:字符串匹配的高频考点
在相关热搜词中,“在kmp算法中,对于模式串p="abacaba",其next数组”这条热词直接命中了KMP算法的考点。字符串匹配是笔试的经典题型,而KMP算法的核心就是next数组(部分匹配表)的求解。
我在面试中经常问候选人这个问题,大多数人的反应是:能写出KMP的匹配主流程,但next数组的求解过程含含糊糊。这说明很多人只记住了代码模板,而没有理解next数组的本质含义——next[i]表示模式串前i个字符组成的子串中,最长相等前后缀的长度。注意,这里的“前后缀”都不包含整个子串自身,因为如果包含自身,那最长相等前后缀永远是子串本身,就没有意义了。
以模式串“abacaba”为例,我们来手动推一遍next数组:
- next[0]:通常初始化为-1(或0,不同教材定义略有差异)
- next[1]:子串“a”,没有真前后缀,所以为0
- next[2]:子串“ab”,前缀a不等于后缀b,所以为0
- next[3]:子串“aba”,前缀a等于后缀a,所以为1
- next[4]:子串“abac”,前缀ab不等于后缀ac,但前缀a不等于后缀c,所以为0
- next[5]:子串“abaca”,前缀ab等于后缀ca?不等。前缀a不等于后缀a?这里要注意,最长相等前后缀为“a”,长度1
- next[6]:子串“abacab”,前缀ab等于后缀ab?是的,“ab”的长度为2,看看有没有更长的?前缀aba和后缀cab不等,所以最长相等前后缀为2
- next[7]:完整模式串“abacaba”,前缀aba等于后缀aba,长度3
这个推导过程看起来简单,但实际笔试中很多人会在细节上出错。我建议大家在推导时写一个辅助表格,把每个位置的子串、所有前缀、所有后缀都列出来,一目了然。
在代码实现中,求next数组用的是一个类似动态规划的递推过程:
def get_next(p): m = len(p) next = [-1] * m i, j = 0, -1 while i < m - 1: if j == -1 or p[i] == p[j]: i += 1 j += 1 next[i] = j else: j = next[j] return next这段代码的精髓在于:当p[i] != p[j]时,j回溯到next[j],而不是j -= 1。这个回溯过程利用了已经计算好的next值,保证了整体时间复杂度是O(m)。如果写成j -= 1,最坏情况下会退化成O(m²)。
在KMP匹配阶段,主串指针不回溯,模式串指针根据next数组回溯,时间复杂度O(n+m)。这个特性在笔试中经常被问到:“为什么KMP比暴力匹配快?”答案是KMP利用了模式串内部的重复结构,避免了主串指针的回溯。
2.3 其他高频数据结构考点:二叉树、哈希表与堆
除了排序和字符串匹配,这套笔试题还涉及了二叉树遍历、哈希表、堆等经典数据结构。
二叉树这块,层序遍历(BFS)和深度优先遍历(DFS)是基础中的基础,但笔试中常考的变种题很多。比如“之字形打印二叉树”“二叉树最近公共祖先”“根据前序和中序遍历重建二叉树”,这些题目在LeetCode上都有原题,建议至少刷两遍。
哈希表的核心考点是哈希函数设计和冲突处理。笔试中常问“哈希表如何解决冲突”,常见答案有开放定址法(线性探测、二次探测)和链地址法。面试官如果追问“为什么Java 8的HashMap在链表长度超过8时转成红黑树”,这就是在考察你对哈希表性能退化问题的理解。当哈希冲突严重时,链表过长会导致查找效率退化为O(n),转成红黑树后降为O(log n)。不过红黑树的实现非常复杂,能在白板上写出来的候选人凤毛麟角,所以笔试题一般不会让手写红黑树。
堆这个数据结构的考点通常集中在“堆排序”和“Top K问题”。尤其是Top K问题,实际业务中太常见了——比如从海量日志中找出访问量最大的10个IP。最优解是用大小为K的小顶堆,维护当前最大的K个元素,时间复杂度O(n log K)。很多候选人第一反应是先排序再取前K个,时间复杂度O(n log n),虽然也能解决问题,但在海量数据场景下性能差很多。面试官想看到的就是你能想到用堆来优化的这一层。
3. 机器学习理论基础:从公式背诵到原理理解
机器学习理论是这套笔试题的另一个重头戏,也是区分“调包侠”和“真工程师”的关键环节。
3.1 模型评估与选择:没有绝对的“最优模型”
这套笔试题中有一类典型问题:如何评估一个分类模型的性能?如何处理过拟合和欠拟合?如何选择模型?
模型评估指标这块,准确率(Accuracy)、精确率(Precision)、召回率(Recall)、F1值、AUC这些概念必须烂熟于心。但更重要的是理解这些指标的适用场景。比如在垃圾邮件检测中,我们更关心精确率(不要把正常邮件误判为垃圾邮件);在癌症筛查中,我们更关心召回率(不要漏掉任何一个可能的患者)。所以面试官问你“用准确率评估一个样本不平衡的二分类模型是否合理”,你要能答出“不合理,因为如果正样本占比只有1%,模型把所有样本预测为负样本也能得到99%的准确率,但这没有意义”,并提出用PR曲线或AUC作为替代方案。
过拟合与欠拟合也是必考知识点。常见的解决过拟合手段包括:增加训练数据、正则化(L1/L2)、Dropout、早停(Early Stopping)、数据增强。关键是要理解每种手段背后的原理:L1正则化为什么能产生稀疏解?因为L1范数在0点不可导,优化过程中更容易把某些特征的权重压缩到0;L2正则化为什么会让权重趋向于小值?因为它在损失函数中加入了一项权重的平方和,梯度下降时会对大权重施加更大的惩罚。能解释到这一层,面试官才会觉得你是真懂。
交叉验证是模型评估中最常用的方法,K折交叉验证、留一法等概念相信大家都熟悉。但有一个细节容易被忽略:交叉验证的划分必须保证训练集和验证集之间没有数据泄露。比如在时间序列场景中,如果随机划分数据,就可能出现用未来数据训练、用过去数据验证的情况,导致评估结果过于乐观。这个问题在实际业务中非常致命,我在面试中会专门出一个小场景题来考察候选人有没有这个意识。
3.2 经典机器学习模型:逻辑回归、决策树、SVM与聚类
机器学习算法的考察点是这套笔试题的核心。逻辑回归、决策树、支持向量机、K-Means聚类、朴素贝叶斯这些经典模型,几乎是校招笔试的必考内容。
逻辑回归是使用最广泛的分类模型之一,考察重点包括:为什么使用sigmoid函数作为激活函数?损失函数为什么是交叉熵而不是均方误差?这里有一个很本质的解释:sigmoid函数把线性回归的输出映射到(0,1)区间,可以解释为概率;而当使用梯度下降优化时,如果使用均方误差,损失函数关于参数的梯度会包含sigmoid的导数项,sigmoid在两端饱和导致梯度消失,训练效率极低。而交叉熵损失函数的梯度形式非常简洁,不含sigmoid导数项,收敛速度快得多。能回答到这个深度,说明你真正理解了逻辑回归的数学原理。
决策树模型的考点集中在特征选择准则上——信息增益(ID3)、信息增益比(C4.5)、基尼指数(CART)。这三个准则的区别是高频考题。信息增益倾向于选择取值多的特征,因为它能把数据集划分得更“纯”,但这容易导致过拟合;信息增益比通过除以特征的固有值(Intrinsic Value)来校正,但也带来了对取值少的特征更偏好的副作用;基尼指数则在计算复杂度和效果之间取得了较好的平衡。如果面试官追问“为什么随机森林中的决策树一般不进行剪枝”,答案是随机森林的随机性(样本采样+特征采样)本身已经起到了正则化的作用。
SVM的考察点通常是“核函数的作用是什么”和“SVM为什么对异常值敏感”。核函数的作用是将低维空间的线性不可分问题映射到高维空间,使其线性可分。但要注意,核函数的选择是有讲究的,RBF核是默认选择,因为它可以逼近任意形状的决策边界,但参数gamma过大会导致过拟合,过小会导致欠拟合。SVM对异常值敏感是因为硬间隔SVM要求所有样本都正确分类,一个离群点就可能导致决策边界剧烈变化,所以实际中常用软间隔SVM,通过松弛变量允许部分样本分类错误。
聚类算法中,K-Means是考察频率最高的。K-Means的原理很简单,但有几个考察点:如何选择K值(肘部法则、轮廓系数);K-Means对初始中心点敏感,如何改进(K-Means++);K-Means假设簇是凸的,对非凸形状的簇效果不好,可以用DBSCAN或谱聚类。还有一个经典讨论:K-Means和GMM(高斯混合模型)的关系。K-Means可以看作GMM的一种特殊情况——当GMM的协方差矩阵趋近于0且各簇的先验概率相等时,EM算法的E步退化为硬分配,M步退化为计算均值,就变成了K-Means。
3.3 优化算法:从梯度下降到群体智能算法
热搜词里出现的“粒子群算法原理”“模拟退火算法”“贪心算法”“PID算法”等,反映出这类搜索优化类算法也是笔试和面试中的常见话题。
在机器学习中,梯度下降是最基础的优化算法,但笔试题很少直接考“梯度下降的公式”,更多是考“随机梯度下降SGD和批量梯度下降BGD的区别”“学习率过大或过小会怎样”“动量项(Momentum)的作用是什么”。SGD每次用一个样本更新参数,计算效率高但更新方向波动大;BGD每次用全量数据计算梯度,更新方向稳定但计算量大;小批量梯度下降Mini-batch GD结合了两者的优点,是实际训练中最常用的方法。学习率过大,参数更新步长太大,容易在最优解附近震荡甚至发散;学习率过小,训练速度太慢。动量项做了什么事?它把历史梯度的一部分加到当前梯度上,相当于给参数更新加了“惯性”,能有效抑制震荡、加速收敛。
粒子群算法(PSO)是群体智能优化算法的代表,其核心思想是模拟鸟群觅食行为。每个粒子有两个属性:位置和速度,位置代表一个候选解,速度为位置更新的方向和大小。粒子在每次迭代中,根据个体历史最优位置(pbest)和群体历史最优位置(gbest)来更新速度,然后更新位置。速度更新公式为:v = wv + c1r1*(pbest - x) + c2r2(gbest - x),其中w是惯性权重,控制粒子对自身速度的保持程度;c1和c2是学习因子,分别控制粒子向个体最优和全局最优学习的程度;r1和r2是[0,1]之间的随机数。理解这个公式的关键是:粒子有三个“引力源”——自身惯量、个体最优记忆、群体最优指引,它们共同决定了粒子的飞行轨迹。
模拟退火算法则借鉴了金属退火的物理过程。算法以一定概率接受比当前解更差的解,且这个概率随着“温度”的降低而减小。接受差解的概率通常由Metropolis准则决定:p = exp(-ΔE / T),其中ΔE是新解与当前解的目标函数差,T是当前温度。这个设计的巧妙之处在于:在算法早期温度高,接受差解的概率大,能够跳出局部最优;随着温度下降,算法逐渐收敛到全局最优附近。笔试中常考“模拟退火和贪心算法的根本区别”,答案是贪心算法只接受更好的解,容易陷入局部最优;而模拟退火能以一定概率接受较差的解,具备跳出局部最优的能力。
3.4 业务场景题:理论与实践之间的桥梁
这套笔试题中最有区分度的部分是业务场景题。通常会给一个具体场景,比如推荐系统、文本分类或者用户画像构建,让你设计方案。
业务场景题没有标准答案,但有一个清晰的解题框架。我在面试中见过不少候选人,不是不懂算法,而是缺乏把业务问题抽象成机器学习问题的能力。以“构建一个用户流失预测模型”为例,一个好的回答应该包含以下步骤:
- 明确任务类型:流失预测是二分类问题,正样本是流失用户,负样本是留存用户。
- 定义样本和标签:时间窗口怎么划分?一个人流失的定义是什么?是连续30天不活跃,还是90天不活跃?
- 特征工程:用户基本属性(注册时长、年龄、性别)、行为特征(最近活跃时间、登录频率、使用时长)、业务特征(付费金额、套餐类型)。
- 选择模型:基线模型用逻辑回归,后续可以尝试XGBoost/LightGBM,注意解释性需求。
- 评估方法:因为正样本比例低,不能只看准确率,结合AUC和PR曲线评估。
- 上线策略:如何做A/B测试?模型预测出流失用户后,用什么策略触达?是发优惠券还是推送消息?
这套框架如果你能逻辑清晰地完整表达出来,就算没有给出具体的参数调优细节,面试官也会觉得你有完整的方法论。
4. 编程题实战:从审题到AC的完整链路
编程题是笔试中压力最大、区分度最高的环节。很多候选人前面理论题答得不错,但编程题直接白卷,非常可惜。下面我梳理一下编程题从审题到AC的完整链路,里面包含了我自己刷题和面试时总结的经验。
4.1 审题与边界条件:70%的人死在第一步
编程题最大的坑不是算法不会,而是审题不清。我见过太多候选人,题目要求“输出结果按字典序排列”,他没注意,直接按输入顺序输出,用例一跑就挂了,非常冤。
拿到题目后,我建议按以下步骤审题:
- 先读输入输出格式:输入是数组还是字符串?有多组测试用例吗?数字范围多大?
- 再明确约束条件:时间复杂度有没有要求?数据量级是10^3还是10^6?这直接决定了能用什么算法。
- 输出格式要看清:每个结果后面有没有空格?要不要换行?保留几位小数?
边界条件是最容易出错的地方。空数组、只有一个元素、元素全是负数或全是正数、最大值和最小值并存的输入,这些用例都要在思考阶段提前覆盖。比如让你求一个数组的最大子数组和,那你要考虑全是负数的情况——这种情况下的答案是数组中最大的那个负数,而不是0。
还有一个容易被忽视的点是数组索引越界。特别是在处理二维数组问题时,要注意矩阵的行数和列数不一致的情况。我建议在写代码时习惯性地加上行列边界判断,避免出现数组越界的低级错误。
4.2 “这道题该用什么算法”的判断方法
很多同学在笔试时最大的困惑是:读完题之后不知道用什么算法。这里我分享一个实战总结的决策思路。
首先看数据规模。如果n小于等于20,大概率可以用暴力枚举或状态压缩DP;如果n在10^5左右,基本不能接受O(n²)的时间复杂度,需要考虑O(n log n)甚至O(n)的算法;如果n在10^6以上,必须用O(n)算法或常数极小的O(n log n)算法。
其次看题目特征。求最值问题,优先考虑贪心、动态规划、二分答案或堆;求方案数问题,优先考虑动态规划或组合数学;求是否存在解的问题,优先考虑哈希表、双指针或并查集;求所有方案的问题,优先考虑回溯法或DFS/BFS。
以常见的“最长上升子序列”为例,经典DP解法是O(n²),但如果告诉你n最大是10^5,就需要用贪心+二分的优化解法,维护一个tails数组,利用二分查找在O(n log n)时间内解决问题。笔试中如果没注意数据范围,直接写O(n²)的版本,虽然本地测试用例能过,但在大数据量测试用例上会超时,导致只能拿到部分分数。
再举一个例子:如果题目要求“在一个字符串中找到第一个只出现一次的字符”,直觉解法是双重循环暴力查找——对每个字符扫描整个字符串,时间复杂度O(n²)。但如果限制字符串长度最大为100万,那就要用哈希表统计频次,第一遍遍历记录每个字符出现次数,第二遍遍历找到第一个频次为1的字符,时间复杂度O(n)。
4.3 经典编程题的代码实现与复杂度分析
动态规划是算法岗笔试题中的高频考点,这里我以一道经典题目为例,展示从状态定义到代码实现的完整过程。
题目:给定一个数组prices,其中prices[i]表示第i天的股票价格。设计算法计算你能获得的最大利润,最多只能完成两次交易。
这个题看起来比“一次交易”复杂不少,但思路其实是层层递进的。核心思路是:把两次交易拆成两个阶段,分别计算“在第i天之前完成第一笔交易的最大利润”和“在第i天之后完成第二笔交易的最大利润”,然后找到两者的最优分割点。
定义dp1[i]为从第0天到第i天最多完成一次交易的最大利润,计算方式是从左往右扫描:
min_price = prices[0] dp1 = [0] * n for i in range(1, n): min_price = min(min_price, prices[i]) dp1[i] = max(dp1[i-1], prices[i] - min_price)再定义dp2[i]为从第i天到第n-1天最多完成一次交易的最大利润,从右往左扫描:
max_price = prices[n-1] dp2 = [0] * n for i in range(n-2, -1, -1): max_price = max(max_price, prices[i]) dp2[i] = max(dp2[i+1], max_price - prices[i])最终答案就是max(dp1[i] + dp2[i+1])。
这个解法的时间复杂度O(n),空间复杂度O(n)。如果面试官要求空间复杂度降为O(1),还有一种更巧妙的解法——状态机DP,用四个变量分别维护第一次买入、第一次卖出、第二次买入、第二次卖掉后的最大收益。这个优化过程很能体现候选人的DP功底,建议大家可以自己推一遍。
4.4 代码风格与调试技巧:工程素养的隐形考察
笔试编程题虽然只要求AC,但代码风格好的候选人在面试官眼中会加分不少。我建议在笔试中养成以下习惯:
变量命名要清晰。写算法题时用i、j做循环变量没问题,但状态转移方程里的含义不同的变量,尽量用有意义的英文单词或缩写。比如用min_price而不是mp,用max_profit而不是mp(容易混淆)。清晰命名不仅方便自己调试,也会给阅卷者留下好印象。
注意代码的“防御性”。在数组访问前判断边界条件,在除法运算前判断分母不为零,在字符串处理时注意空字符串。这些细节能在笔试中救你一命。
调试技巧方面,建议在本地IDE中多写几个test case,特别是边界case。比如排序算法,一定要测空数组、单元素数组、已排序数组、逆序数组、包含重复元素的数组。如果笔试环境支持本地编译运行,一定不要偷懒跳过自测环节。如果环境不支持本地调试,也可以在代码中临时加入print语句打印中间结果,跑几个小规模用例确认逻辑无误后再提交。
5. 备考策略:从这套题反推复习路径
聊完这套题的具体考点,最后聊聊怎么备考。很多同学到秋招时才如梦初醒,开始疯狂刷题,但其实算法岗的笔试准备是一个系统性的工程,需要合理规划时间。
5.1 分阶段备考:基础、刷题、模拟三步走
第一阶段是打基础,建议用1到2个月的时间系统复习数据结构和机器学习理论。数据结构部分重点复习数组、链表、栈、队列、哈希表、二叉树、堆、图;机器学习部分重点复习模型评估、线性模型、决策树、SVM、聚类、集成学习、深度学习基础。参考书籍方面,周志华的《机器学习》(西瓜书)是经典中的经典,配合李航的《统计学习方法》一起看效果更好。如果时间紧张,至少要把西瓜书的前八章吃透。
第二阶段是刷题,建议每天固定2到3小时。主刷LeetCode,按照“数组、字符串、链表、树、动态规划、贪心、回溯、图”的顺序逐个击破。刚开始可以按专题刷,每个专题刷20到30道题,等基本套路熟练后,再刷随机题模拟真实笔试场景。面试前一个月,可以直接刷LeetCode Hot 100和面试高频题清单。这里特别提醒:不要只看题解就算刷过了,必须要自己动手写,写不出来就对照题解逐行理解,然后关掉题解重新写一遍。写代码能力是“手上功夫”,看再多不写等于零。
第三阶段是模拟笔试。找一些公司往年的真题,严格计时,模拟真实的笔试环境。比如这道iHandy的笔试题,你就可以给自己定一个90分钟的时限,一次性完成所有题目。模拟的目的不只是检验知识储备,更是训练时间分配能力——哪类题该快速跳过、哪类题值得花时间多想,都需要在模拟中摸索出策略。
5.2 资料选择与避坑指南
资料不在多,贵在吃透。我推荐三份核心资料:《机器学习》(周志华)、《统计学习方法》(李航)和LeetCode题库。如果你的基础偏弱,可以先看吴恩达的Coursera机器学习课程建立直觉,然后回到书面教材补理论细节。
关于“机器学习模型”的复习,我不建议零散地刷网上的博客和公众号文章。虽然有些文章写得很好,但信息碎片化严重,容易造成“看了很多但脑子里没有系统框架”的错觉。正确的做法是:以教材为主线建立知识框架,再用碎片化文章填补细节和最新进展。
再来说说避坑。一个常见的误区是准备算法岗笔试时过度钻研深度学习框架的底层源码,比如自己推一遍Transformer的attention公式、手写一个YOLO的损失函数。这些内容在面试中可能会被问到,但不应该是笔试准备的主要方向。笔试题更看重基础算法的扎实程度和机器学习理论的广度,深度学习的深水区更适合放在面试环节展示。时间有限,要把精力花在性价比最高的地方。
另一个误区是忽略数学基础。机器学习笔试中的很多公式推导题目,本质上考的是线性代数、概率论和微积分。比如逻辑回归的损失函数推导需要用到最大似然估计,SVM的对偶问题推导需要用到拉格朗日乘子法。如果大学数学基础不牢,建议花时间复习一遍线性代数中的矩阵求导、特征值分解,概率论中的常用分布、最大似然估计,以及最优化理论中的梯度下降、拉格朗日对偶。
5.3 实战经验:笔试过程中的心态与策略
最后分享一些笔试现场的实战经验。首先是时间分配,我个人的习惯是“先易后难,确保送分题满分”。拿到试卷后先快速浏览所有题目,标记出哪些是基础题、哪些是拔高题。优先完成基础题,确保不丢分,再集中精力攻克拔高题。编程题如果一道题卡了20分钟还没思路,果断先跳过,做后面的题目,最后再回来攻坚。不要在一道题上死磕,导致其他题目没时间作答,这是很多候选人最常犯的错误。
其次是心态管理。笔试过程中遇到不会的题目太正常了,不要因此慌了阵脚。一道题不会直接跳过,保持节奏比什么都重要。我当年笔试时遇到一道“概率题+DP”结合的难题,完全没有思路,果断放弃,把省下来的时间检查前面的题目,确保会做的全对,最后依然进入了面试环节。笔试的目标不是满分,而是拿到足够进面的分数。
最后是复盘。笔试结束后不管你自我感觉如何,建议把题目和你的答案记录下来。如果通过了,面试可能会追问笔试中的某些题目;如果没通过,这套题就是最好的复习材料。找出不会的知识点,回头看书补课,下次面试时就是经验值+1。
6. 写在最后:算法工程师这条路,基础决定高度
回到iHandy这套2019校招笔试题,虽然已经过去几年了,但它的考点分布和难度设计,放在今天的校招市场中依然不过时。数据结构、经典算法、机器学习理论、业务场景分析,这些构成了一名算法工程师的基本盘。技术圈的热点一直在变,今天是大模型,明天是具身智能,但扎实的基础永远不会过时。
我在实际带人的过程中有个很深的体会:基础扎实的工程师,学习新技术的速度远超基础薄弱的人。原因很简单,新技术无非是旧知识的组合和升级。你理解了注意力机制,就更容易理解Transformer;你理解了GBDT,就更容易理解XGBoost和LightGBM。反过来,如果你连决策树的基尼指数都说不清楚,给你讲GBDT只会听得一头雾水。
所以,如果你正在准备校招,或者打算转行做算法,我的建议是:不要被各种“速成”和“捷径”诱惑,老老实实打基础、刷题、做项目,这条路虽然慢,但每一步都算数。这套笔试题就像一面镜子,照出你的知识盲区,别怕照出问题,怕的是看到问题还不去补。
最后再分享一个小技巧:准备笔试时,把每一道错题都整理到自己的错题本里,记录三样东西——题目、错误原因、正确思路。秋招季你可能要投几十家公司,做十几套笔试题,错题本就是你最宝贵的复习资料。我当年就是靠着这个错题本,在同班同学还在海投简历的时候,提前拿到了心仪的offer。希望这份经验也能帮到你。