ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

2024秋招淘天算法岗笔试复盘:KMP、动态规划与机器学习考点精析

2024秋招淘天算法岗笔试复盘:KMP、动态规划与机器学习考点精析 2024年秋招阿里淘天算法岗第二批笔试我是在国庆假期后第三天参加的。整体感受是题型没有变难度稳中有升选择题的AI/ML浓度明显加重编程题依旧硬核但相比于第一批的“防AK”风格第二批其实更看重你把基础算法写稳的能力。这篇文章就把我自己的考场经历、题目记忆、复盘思路和备考建议完整记录下来给后面想冲大厂算法岗的同学做个参考。先说结论淘天这批笔试选择题决定了你能不能进面试编程题决定了面试官第一眼怎么看你。三题全AC的简历和只AC一题的简历在后续流程中的关注度差异是肉眼可见的。所以别只看“过没过”要把每一道编程题都当成展示自己的机会。1. 笔试基本信息与整体节奏把控1.1 考试平台与时间分配这次笔试用的是牛客网总共120分钟题目结构是单选题15道、多选题5道、编程题3道。总分100分其中选择题一共占40分每题2分编程题占60分每题20分。但这个分值分布在不同批次里可能微调仅供参考。很多人会忽略一个关键点牛客网的编程题不同语言的时间限制和内存限制不一样而且编译器的优化级别也不一样。我在考场上用C提交明显感觉到对复杂度的要求比往年更严格O(n^2)的暴力解法在数据量稍大的用例上直接TLE。我建议你提前在牛客网上用目标语言做几套模拟题摸清楚它那套在线评测环境的脾气。时间分配上我的策略是先花30到35分钟解决编程题里最有把握的两道再回头做选择题最后剩下30分钟左右死磕最难的第三题。原因很简单——编程题一题20分是你完全能掌控的分数选择题哪怕是蒙也有概率得分但编程题如果时间不够连暴力分都骗不到。1.2 题型分布特征第二批笔试的选择题内容覆盖面比第一批更广除了常规的数据结构、操作系统、计算机网络还加入了大量机器学习、深度学习的基础题。我粗略统计了一下约40%的题目都在考AI/ML相关基础这跟淘天算法岗的实际业务方向推荐、搜索、广告、多模态是对应的他们确实需要理论基础扎实的人。而编程题部分动态规划依然是绝对核心有一道贪心堆的优化题还有一道KMP相关字符串题。三题难度呈明显的梯度第一题是给保底的送分题第二题是区分“刷过题”和“没刷过题”的分水岭第三题则是用来筛选真正能打硬仗的人。2. 选择题核心考点复盘数据结构和算法基础2.1 KMP算法与next数组的经典考点热搜词里反复出现KMP这次笔试也确实考了。原题我记得大概是给定模式串 pabacaba要求写出其 next 数组有的版本叫失配数组或者部分匹配表。这类题在笔试中几乎是“必考题”你躲得过这批躲不过下批。KMP的next数组计算有个容易混淆的地方不同教材里next数组的定义有两种流派。一种是“当前字符之前的字符串中最长相等前后缀长度”另一种是“当前位置匹配失败时模式串指针跳转的位置”。这两种定义算出来的数组值会差一位网上有些资料经常不标说明直接给答案导致很多人越看越乱。我建议你掌握一种即可并在考场上留意题目给出的定义。按最常见的定义pabacaba的next数组逐位计算如下p a b a c a b a next 0 0 1 0 1 2 3具体过程下标0的next是0或-1取决于定义下标1的b它前面只有a没有相等前后缀所以是0下标2的a它前面的字符串是ab最长相等前后缀是a长度为1所以next[2]1下标3是c前面是aba前缀a和后缀a相等但前缀ab和后缀ba不相等所以最长也是1不对这里要重新算——字符串aba的最长相等前后缀其实是a长度1所以next[3]1。但前面写0是错的我重新梳理一下next[0] 0next[1]在位置1失配时看子串a下标0到0最长相等前后缀长度是0next[2]看子串ab前缀a、后缀b不等最长相等前后缀为0next[3]看子串aba前缀a、后缀a相等长度1前缀ab、后缀ba不等所以为1next[4]看子串abac前缀a、后缀c不等为0next[5]看子串abaca前缀a后缀a长度1前缀ab后缀ca不等前缀aba后缀aca不等所以为1next[6]看子串abacab前缀ab后缀ab长度2再长就没了所以为2next[7]看整个串abacaba前缀aba后缀aba长度3所以为3所以正确的next数组按最长相等前后缀定义是0 0 0 1 0 1 2 3其中next[7]有时不写因为它是为“整个串匹配完成后”服务的。如果是另一种定义失配跳转位置整体减1再偏移结果会变成-1 0 0 1 0 1 2。这就是很多人对答案发现对不上的原因。注意做题前一定要先看题目里next数组的下标起点是0还是1以及定义是“长度”还是“跳转位置”这决定了最终答案形态。我自己就曾在定义上吃过亏多花了两分钟。2.2 排序算法的稳定性和复杂度边界这次笔试也考了几道排序相关的题其中一个点就是各类排序算法的稳定性。为什么大厂笔试总爱考这个因为在实际业务里排序稳定性有时候会直接影响最终结果。我举个例子你在电商场景里要先按商品价格排序再按销量排序如果第二次排序算法不稳定价格相同的那批商品内部顺序就乱掉了最终展示结果就不符合预期。基础结论直接背下来稳定排序插入排序、冒泡排序、归并排序、基数排序不稳定排序选择排序、希尔排序、快速排序、堆排序但考试不只考记忆还考理解。比如问“快速排序在什么情况下时间复杂度退化到O(n^2)”答案是当每次划分都极端不平衡时比如对已经有序的数组用固定基准值。解决办法是随机选基准点或者三数取中。这一类的“为什么”比“是什么”更能拉开分差。2.3 贪心算法与动态规划的边界判断有一道选择题问下列哪个场景适合用贪心算法选项给的是区间调度、0-1背包、最短路径、编辑距离。答案是区间调度。这里其实在考你能否区分“贪心能解”和“贪心不能解”的问题边界。我见过很多人分不清核心原因是他们只记题目不记判断标准。贪心算法成立的充分条件有两个贪心选择性质和最优子结构。简单来说就是“每一步做局部最优选择最终能得到全局最优解”。区间调度问题之所以适合贪心是因为它按结束时间排序后优先选结束早的区间一定能给后续区间留出最大空间局部最优可以递推到全局最优。而0-1背包不具备这个性质因为你不能为了当前价值最大的物品而丢弃整体搭配最优的方案所以要用DP。这类题其实是在考察算法思维模型不是单纯刷题能解决的。建议你复习时把每种经典算法的适用场景整理成一张表考前过一遍。3. 编程题真题思路与AC代码复盘3.1 第一题最小区间覆盖贪心排序这题是典型的保底题考的是贪心算法的经典应用区间覆盖。题目大意是给定一个目标区间[m, n]和若干个小区间每个小区间有左端点和右端点问最少选择多少个小区间能完全覆盖目标区间如果无法覆盖输出-1。思路非常直接先把所有区间按左端点升序排序然后维护当前已覆盖到的最右位置cur和下一个能够扩展的最右位置next。从左到右遍历区间凡是左端点小于等于cur的区间都把它们右端点拿来更新next取最大遍历完一轮后如果next等于cur说明中间有断层直接输出-1否则答案加1cur更新为next继续下一轮。实际上这是区间调度里很典型的“最少区间覆盖”问题难度在LeetCode上大概算中等偏低。考场上的坑不是思路而是边界处理目标区间的左端点可能不是0区间之间可能有重叠也可能有空隙。我写的时候用了一个小技巧把区间按左端点排序后用一个变量维护当前覆盖位置每次选择左端点不大于当前覆盖位置且右端点最大的那个区间。#include bits/stdc.h using namespace std; int main() { int m, n, N; cin m n N; vectorpairint,int segs; for (int i 0; i N; i) { int l, r; cin l r; if (r m || l n) continue; segs.push_back({l, r}); } sort(segs.begin(), segs.end()); int cur m, idx 0, ans 0; while (cur n) { int nxt cur; while (idx segs.size() segs[idx].first cur) { nxt max(nxt, segs[idx].second); idx; } if (nxt cur) { cout -1 endl; return 0; } ans; cur nxt; } cout ans endl; return 0; }这段代码的核心思想是“贪心扩展最右端”每次从所有能接上的区间里挑右端点最远的这样可以保证用的区间数最少。时间复杂度是排序的O(NlogN)后面线性扫描一遍整体就O(NlogN)。3.2 第二题带权重的最长递增子序列变体DP二分第二题开始上强度了。题目背景是你有一个序列每个元素有数值和权重两个属性。要求选出一个子序列使得数值严格递增同时总权重最大。输出最大总权重。这题本质上是一个“带权最长递增子序列”问题经典LIS只统计长度这里要求最大化权重和。暴力DP很容易想dp[i]表示以第i个元素结尾的最大权重转移时遍历前面所有数值比它小的元素dp[i] max(dp[j]) weight[i]复杂度O(n^2)。但题目数据范围n可以达到10^5O(n^2)必挂。所以需要优化。优化思路是用线段树或树状数组维护“按数值分桶的区间最大值”。先把数值离散化然后从左到右遍历每个元素查询所有数值小于当前值的dp最大值加上当前权重再更新到当前数值这个桶里。每次查询和更新都是O(logn)总复杂度O(nlogn)。我当时选择的是线段树因为树状数组求前缀最大值需要额外处理下标偏移。线段树写起来更直观也方便面试时讲清楚。核心代码如下#include bits/stdc.h using namespace std; vectorint val, weight; vectorlong long tree; void update(int node, int l, int r, int pos, long long v) { if (l r) { tree[node] max(tree[node], v); return; } int mid (l r) 1; if (pos mid) update(node1, l, mid, pos, v); else update(node1|1, mid1, r, pos, v); tree[node] max(tree[node1], tree[node1|1]); } long long query(int node, int l, int r, int ql, int qr) { if (ql r || qr l) return 0; if (ql l r qr) return tree[node]; int mid (l r) 1; return max(query(node1, l, mid, ql, qr), query(node1|1, mid1, r, ql, qr)); } int main() { int n; cin n; val.resize(n); weight.resize(n); vectorint tmp(n); for (int i 0; i n; i) { cin val[i]; tmp[i] val[i]; } for (int i 0; i n; i) cin weight[i]; sort(tmp.begin(), tmp.end()); tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end()); tree.assign(4 * tmp.size() 5, 0); long long ans 0; for (int i 0; i n; i) { int idx lower_bound(tmp.begin(), tmp.end(), val[i]) - tmp.begin() 1; long long best query(1, 1, tmp.size(), 1, idx - 1); best weight[i]; ans max(ans, best); update(1, 1, tmp.size(), idx, best); } cout ans endl; return 0; }我的考场心得是这类题最容易错的地方其实是离散化和查询边界一旦把数值相等的元素也当成可递增的就会导致错误。题目说“严格递增”所以查询时只能查当前数值之前的值也就是idx-1之前。3.3 第三题字符串循环节问题KMP应用第三题是压轴题一开始我还以为是后缀数组或者AC自动机仔细读题后才发现是个KMP的经典应用给定一个字符串s问是否存在一个更短的字符串t使得t不断重复若干次后能得到s。如果存在输出最短的t的长度如果不存在输出原字符串长度。其实这题就是LeetCode上的重复子字符串问题判断字符串是否能由其某个子串重复构成。解法分两步第一用KMP求出整个字符串的next数组第二记n为字符串长度令len n - next[n]。如果n % len 0说明循环节存在最短循环节长度就是len否则就不存在循环节。原理在于next[n]表示整个字符串的最长相等前后缀如果字符串是循环串那么循环节的长度恰好是n减去这个最长相等前后缀的长度。举一个简单的例子sabababn6next[6]4最长相等前后缀是abab那么len6-42且6%20所以最短循环节是ab答案是2。再比如sabcabn5next[5]2len3但5%3!0所以没有循环节输出5。这题真正的难点在于KMP的next数组你得写对。考场上一紧张下标偏移很容易出错。我建议你平时在IDE里把KMP模板跑顺了最好能达到“闭着眼睛都能写出来”的程度。字符串题就是这样模板熟了思路就快思路快了剩下的时间都能留给第三题。#include bits/stdc.h using namespace std; vectorint getNext(const string p) { int m p.size(); vectorint next(m 1, 0); for (int i 1, j 0; i m; i) { while (j 0 p[i] ! p[j]) j next[j]; if (p[i] p[j]) j; next[i 1] j; } return next; } int main() { string s; cin s; int n s.size(); vectorint next getNext(s); int len n - next[n]; if (n % len 0) cout len endl; else cout n endl; return 0; }考场陷阱是题目如果问的是“能否通过拼接多个相同子串得到”那原字符串本身也是自己的一倍这不算。所以如果n%len0且lenn输出是n这道题的case里就专门有一个这样的字符串去卡那些没想清楚的选手。4. 机器学习理论基础选择题里的隐藏得分点4.1 模型评估指标与过拟合处理近两年算法岗笔试选择题里机器学习相关占比越来越高。这批考试里有一道多选题是关于分类模型评估的给了准确率、精确率、召回率、F1和AUC五个选项问哪些指标不受正负样本不平衡的影响。答案是AUC和F1不对准确率受不平衡影响最大精确率/召回率也受影响AUCROC曲线下面积对样本比例不敏感。F1由精确率和召回率调和得到它在正样本极少时也会显著偏低所以严格来说只有AUC最稳。这里我多说一句AUC是算法岗必须理解的指标它衡量的是“随机抽一个正样本和随机抽一个负样本模型给正样本打分更高的概率”所以它天然与样本比例无关。有的同学只会背概念考试换几个说法就懵了建议你在项目里多手动计算几次AUC把原理刻进脑子里。过拟合也是高频考点。那次笔试考的是下列哪些手段能缓解过拟合常规答案有L1/L2正则化、Dropout、数据增强、早停、降低模型复杂度。但选项里混了一个“增加训练轮数”要你识别出来这是加剧过拟合的。这种题没有难度考的是你是否真的理解正则化的作用机制而不是背答案。4.2 常见机器学习算法原理辨析第二批笔试还考了聚类、KNN和决策树相关的内容。有一道题问KNN的K值大小对模型的影响选项涉及偏差方差权衡。简单来说K值越小模型越复杂容易过拟合方差大K值越大模型越简单但可能欠拟合偏差大。决策树那边问的是信息增益的计算。给你一个小数据集要你算某个特征分裂后的信息增益是多少。这题属于计算题你要会算熵和信息增益。公式不复杂信息熵 H(D) -Σp_i * log2(p_i)信息增益 Gain(D, A) H(D) - Σ(|D_v| / |D|) * H(D_v)后来我在复盘时发现这道题其实有更快的算法如果某个特征能把数据集划分得非常“纯”即每个子集里基本都是同一类信息增益就大。反之划分后依然混杂增益就小。用这个直觉判断有些选择题甚至不用精确计算扫一眼选项就能排除一大半。4.3 深度学习基础与Transformer常识Deep Learning这边考察的题量也不少主要是基础概念。有一道题问深度学习模型训练时梯度消失的主要原因正确选项是“连乘导致的梯度衰减”。链式法则让反向传播的梯度经过多层后越来越小特别是在使用Sigmoid这类导数最大值只有0.25的激活函数时梯度消失几乎是必然的。这也就是为什么ReLU能成为主流激活函数它正区间导数恒为1能有效缓解梯度消失。Transformer相关考了一道常规题self-attention的计算时间复杂度是多少答案是O(n^2 * d)其中n为序列长度d为隐层维度。模型界现在很多人研究如何把注意力机制从O(n^2)降到O(n)比如线性注意力、稀疏注意力等但基础的scaled dot-product attention复杂度就是O(n^2)。这类送分题不要丢。我的体会是机器学习理论部分的复习不要追求“什么都懂”而是要把高频考点评估指标、过拟合、经典算法、激活函数、注意力机制牢牢吃透。淘天算法岗更看重的不是你会多前沿的模型而是你的基础能不能支撑起业务场景里的需求分析。5. 实操经验考场上的时间管理与骗分策略5.1 高效拿分的做题顺序很多同学的做题习惯是从头做到尾选择题卡住了也不跳过。这是大忌。笔试总共120分钟如果你在选择题上花超过40分钟编程题大概率做不完。我的策略是先花两三分钟快速浏览所有题目把编程题分成“会做”“思路模糊”“完全没头绪”三档。第一档直接写争取一次AC第二档先留思路在草稿纸上等完成第一档再回头实现第三档放到最后用暴力解法先骗部分分数。有一年我遇到第三题的图上DP完全没思路但我把暴力枚举写出来了过了30%的测试点最终靠着这30%的分混进了面试。这个策略在任何大厂笔试里都管用。5.2 牛客在线评测的环境差异牛客网和力扣的输入输出方式不同它是标准输入输出模式需要你自己写main函数自己处理输入的分隔符和换行。每年都有人因为不熟悉牛客的IO写法而挂掉真的很冤。比如读一个可能有逗号分隔的数组你要自己处理vectorint arr; string line, token; getline(cin, line); stringstream ss(line); while (getline(ss, token, ,)) { arr.push_back(stoi(token)); }这类代码没有难度但是考场上临时想很容易出错。我建议你在备考阶段就专门用牛客网的模拟系统练IO尤其是C的cin/cout关同步、getline和stringstream的组合用法以及输入数据中可能混入的空行。5.3 暴力解法与部分分的骗分技巧淘天的笔试评分规则里编程题是典型的“部分AC”模式你通过多少测试点就得多少分。很多同学看题目没思路就直接放弃这是最大的浪费。其实大厂的测评数据里必定包含小规模数据的测试用例暴力算法完全可以拿到20%-40%的分数。暴力骗分有一些固定套路如果题目要求求最大值或最小值可以先写全排列或DFS枚举所有可能n较小的时候能跑出正确结果。如果题目涉及区间操作可以先用最朴素的模拟不做任何优化至少能处理小数据。如果题目是图上问题可以先只处理最简单的情况比如链式图或树形图一般会有对应的小数据子任务。我还见过一些人在考试最后几分钟直接打印样例输出期望的结果期望能骗到一两个测试点这在牛客上一般行不通但如果你真的没办法了也不失为一种选择。关键是不要留空。6. 常见问题与备考避坑从别人的失败里学习6.1 知识点掌握不深导致的选择题连环翻车我认识一个朋友算法题刷了500多道但机器学习基础薄弱结果淘天笔试的选择题错了一半最后编程题虽然两题AC总分还是被拉低到没进面试。这其实是非常典型的案例算法岗的笔试不是单纯的算法竞赛它还要考核你对AI基础的掌握程度。校招笔试的选择题特点就是“广而不深”覆盖OS、网络、数据库、ML、DL、数据结构、算法设计等多个方向。你很难在短期内全部精通但至少要把高频考点过一遍。我个人推荐的做法是刷一遍《机器学习》西瓜书的重点章节再加上李航的《统计学习方法》中的主要算法推导Transformer部分可以看原论文或者比较好的中文解读。这些知识不需要你全部推导但至少选择题里碰见不陌生。6.2 只看题解不手写代码导致的考场手生很多同学平时刷题是在编辑器里看题解自己照着敲一遍AC了就过。这样会产生一种“我完全掌握了”的错觉。但考场上没有题解可以参考各种边界条件、数据类型、数组下标偏移都会让你的代码从“能跑”变成“跑不过”。我的经验是准备秋招的冲刺阶段每天至少抽1小时做限时手写代码训练。不用多两到三道中高难度的题在15-25分钟内完成。重点是训练“从读题到AC”的完整链路尤其是输入输出处理、边界条件判断和代码风格这三块。很多人栽在边界条件上比如数组长度为0、输入中混有换行符、整数溢出这些都是笔试中极其常见的坑。6.3 心态失衡与题目阅读错误第三题如果卡住超过20分钟我会建议你立刻放手先检查前面两题有没有隐藏问题再回头重新读第三题的题目。很多压轴题其实并不难只是题目描述长或者背景包装得花哨导致你读了三遍都没抓住关键。我这次考场上第三题读题花了整整5分钟一度以为是要写字符串哈希后来才意识到是KMP的循环节判断。读题技巧总结先看输入输出样例再倒推题目要求。样例能让你迅速知道程序该接收什么、输出什么如果输入输出明白了题目中九成的文字描述都只是背景故事可以直接过滤掉。另外提醒一点笔试过程中一定要留意题目里的“保证”二字例如“保证输入不超过10^5”“保证答案在int范围内”这些信息直接决定你选择的数据类型和算法复杂度。很多人没注意到题目中的这些关键词结果用了int导致溢出或者以为需要高精度白白浪费了时间。6.4 备选计划永远要有笔试前一定要准备一个Plan B以防考试中遇到设备问题或者断网。牛客网支持在线考试但偶尔会有浏览器兼容性问题或编辑器闪退。提前准备好本地的IDE并把常用模板KMP、树状数组、线段树、并查集、最短路、前缀和存到本地代码片段里虽然在线笔试一般不允许本地IDE辅助但万一口试或加面需要手写时这些模板就是你最后的底气。我的个人习惯是在GitHub建一个私有仓库把常用算法模板分门别类整理好考前刷一遍考试前一天就不再看新题了只复习模板和看错题本。这样上场的时候心态比较稳遇到相似题型的反应速度也快。7. 后续流程预测与备面建议7.1 笔试后的等待期该做什么笔试结束到收到面试通知中间可能隔几天到两周不等。别傻等这段时间是黄金备面期。淘天算法岗的面试通常有两到三轮技术面加一轮HR面技术面里高频考察的是机器学习基础、深度学习原理、项目经历深挖、手撕算法/代码以及业务场景设计题。笔试里暴露出来的知识漏洞一定要在面试前补齐。我自己的做法是把笔试错题整理成文档标注每道题对应的知识点然后针对每个薄弱点做专项复习。比如我那次选择题在规范化一致性和Transformer细节上失分后面就专门把这两块重新推导了一遍面试时果然被问到了类似概念。7.2 技术面试中的手撕代码风格淘天的技术面几乎必考手撕代码常见考察形式是面试官在共享白板上让你写一道题或者给你一个在线代码编辑器的链接。这时候代码规范性和思路表达比你想象中更重要。面试官不只看你有没有AC更看你在写代码过程中的思维链条。我总结的面试代码加分项先说要用什么算法和数据结构再说时间/空间复杂度然后才开始写写的过程中用注释标出关键步骤写完主动跑一遍样例并对边界情况做验证。这些都是在校招面试里非常加分的习惯比默默敲完然后一句话不说强一百倍。7.3 业务场景题的核心套路淘天面试特别喜欢结合业务场景提问这是算法岗区别于纯研究岗的地方。比如“如何为首页推荐做冷启动”“如何预估某类商品的点击率”“如何平衡推荐的多样性和相关性”这类问题没有标准答案但有固定的答题框架明确目标、拆解问题、选择合适的模型或策略、评估指标设计、上线及AB测试。应对这类题的关键是你对常用模型和业界常识的积累例如推荐系统里的召回、粗排、精排、重排链路是怎么划分的排序模型常用的LR、GBDT、DeepFM等有哪些优缺点。笔试阶段可能不会直接考到这些但如果你能早早开始准备后面面试会轻松很多。8. 我个人实战后的经验总结这次淘天第二批笔试我最深的体会是算法岗的笔试考验的不只是算法而是综合实力。选择题考你基础知识的广度和精度编程题考你代码实现的稳定性和算法优化意识整场考试的时间压力则在心理层面筛选掉一批人。把时间线拉长到整个秋招看一场笔试的成败并不会决定你的全部但它确实是很多公司筛人的第一道硬门槛。你能做的就是在每一次模拟笔试里尽量还原真实考场的节奏和环境让自己在真正上考场时像个“考试老手”一样从容。最后分享一个小技巧是我刷题以来一直坚持的习惯每做完一套模拟卷不管成绩如何都写下三句话的复盘——这套卷子最大的知识盲区是什么、如果再做一次我能在哪里省时间、这个知识点在其他题目里还能怎么变形。坚持一个月你对算法考点的敏感度会明显提升而不是停留在“刷了多少道题”的自我感动里。希望这次的复盘能帮到你祝秋招顺利。
返回列表