尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

爱奇艺算法岗秋招笔试复盘:从KMP到卡尔曼滤波的考点全解析

爱奇艺算法岗秋招笔试复盘:从KMP到卡尔曼滤波的考点全解析 又到秋招季整理资料时翻到当年那份爱奇艺2018秋季校招算法工程师第一场的笔试记录很多细节一下子涌了回来。这场笔试覆盖了数据结构、机器学习、图像处理与视频工程等多个方向题型和难度在同级别公司里很有代表性。我当年在这套题上踩过不少坑后来把整个考点梳理成了一套完整的学习路径也帮不少学弟学妹做过复盘。今天把这套考点解析和实操经验整理出来给正在准备算法岗笔试的你一个参考。整场笔试给我最直观的感受是不偏不怪但覆盖面非常广。只要基础扎实、节奏控制好是能拿到不错分数的。但反过来说如果复习时只盯着某一类题型就容易在综合题上栽跟头。下面我从题型分布讲到核心考点再结合我自己的答题经历把这场笔试真正想考察的东西拆开讲清楚。1. 笔试整体复盘题型分布与考察逻辑1.1 题量与时间分配先说整体印象。爱奇艺这场笔试大约2小时题目结构是“选择题 编程题 简答题”混排。选择题大概20道覆盖数据结构、算法复杂度、机器学习基础编程题2到3道集中在字符串、动态规划、排序变形简答题一般有1到2道会结合具体的视频场景出题比如“设计一个视频推荐召回策略”这类开放性问题。2小时看起来够用实际做起来非常紧凑。我的经验是拿到试卷先花8到10分钟把全部题目快速过一遍标记出有把握的题和需要思考的题。先做有把握的再做需要推导的最后处理完全没思路的。编程题如果一上来就死磕难题很容易导致后面的选择题没时间做得不偿失。时间分配上我建议选择题平均每题控制在1.5分钟以内编程题先留10分钟读题和设计思路再开始写代码简答题至少留15分钟。我见过不少同学因为时间分配不合理最后简答题只写了两行字非常可惜。简答题往往分值高、区分度大哪怕不会也要把能想到的要点列上去不能空着。1.2 三类必考模块的底层逻辑从企业视角看一场算法笔试不可能把每个方向都考一遍它本质上只考察三件事算法基础是否扎实、机器学习理解是否到位、能否把算法落地到具体业务场景中。第一算法基础。主要考察数据结构和经典算法判断你有没有扎实的编码功底。这类题通常不偏不怪但考场压力下人容易犯错。字符串处理、排序、搜索、动态规划是四个出现频率最高的方向。第二机器学习理解。重点考察模型原理、损失函数、过拟合和调参思路。算法工程师的日常工作就是和模型打交道如果对基本概念理解不深很难胜任后续工作。第三工程落地能力。通过结合业务场景的题目判断你能不能把算法用在真实业务里。对爱奇艺这种视频平台来说推荐、搜索、视频理解就是最核心的应用场景。所以笔试里会出现图像处理、视频算法、搜索排序相关的内容。理解了这个逻辑复习时就不会胡子眉毛一把抓。我当时就是按这个框架划重点的先突破数据结构与算法基础再系统梳理机器学习核心概念最后针对视频平台场景做专项准备。事实证明确实高效方向对了努力才有效。2. 数据结构与经典算法那些必须拿下的送分题2.1 KMP算法与next数组从“abacaba”看字符串匹配的现场推导KMP算法是笔试里出现频率非常高的考点几乎每一届校招都会考。热词里那道“对于模式串p‘abacaba’其next数组是多少”的题目就是典型的字符串匹配基础题。这种题看起来简单但很多人在考场上一紧张就推错核心原因是对next数组的定义理解不到位。先明确两种主流定义。不同的教材和题库对next数组的定义有差异定义A算法竞赛、LeetCode风格next[i]表示p[0..i-1]这个前缀子串的最长相等真前后缀长度且next[0]-1。含义是如果模式串在位置i失配主串指针不回退模式串跳到next[i]位置继续比较。定义B严蔚敏《数据结构》版next[i]表示模式串第i个字符失配时应跳转的位置索引从1开始next[1]0。我们先用定义A来完整推导p\“abacaba\”的next数组。先把模式串列出来索引从0开始索引0123456字符abacaba推导过程next[0] -1固定值。next[1]考察p[0..0]“a”真前缀和真后缀都为空集最长相等长度0。next[2]考察p[0..1]“ab”前缀有{a}后缀有{b}无相等为0。next[3]考察p[0..2]“aba”前缀{a, ab}后缀{a, ba}最长相等为“a”长度1。next[4]考察p[0..3]“abac”前缀{a, ab, aba}后缀{c, ac, bac}无相等为0。next[5]考察p[0..4]“abaca”前缀{a, ab, aba, abac}后缀{a, ca, aca, baca}最长相等“a”长度1。next[6]考察p[0..5]“abacab”前缀{a, ab, aba, abac, abaca}后缀{b, ab, cab, acab, bacab}最长相等“ab”长度2。next[7]考察p[0..6]“abacaba”前缀{a, ab, aba, abac, abaca, abacab}后缀{a, ba, aba, caba, acaba, bacaba}最长相等“aba”长度3。所以定义A下的next数组是[-1, 0, 0, 1, 0, 1, 2, 3]。如果题目用定义B结果则是[0, 1, 1, 2, 1, 2, 3]索引从1开始每一位对应失配时的跳转位置。遇到这类题先审清题目要求的是哪种定义再动手这是必须养成的习惯。实际操作时我推荐大家掌握“递推 回退”的理解方式不要死记硬背。next数组的构建过程本质上就是“模式串匹配自身”用两个指针i和ji遍历模式串j表示当前已匹配的前缀长度。当p[i] p[j]时next[i1] j1i和j都加1如果不相等j回退到next[j]。这个思路在考场写代码时最不容易出错也不容易漏掉边界情况。2.2 排序与堆手写堆排序的边界陷阱排序算法是笔试选择题和编程题的常客热词里同时出现了“冒泡排序算法c”“堆排序算法”“数据结构排序算法”说明这是整个校招季的高频考点。选择题喜欢让你比较各种排序算法的复杂度和稳定性编程题则可能让你手写某个排序。以堆排序为例手写堆排序常见的坑有三个第一建堆时要从最后一个非叶子节点开始向下调整。很多人习惯从数组末尾开始结果调整逻辑完全出错。最后一个非叶子节点的下标是n/2 - 1n为数组长度因为再往后的节点都是叶子节点叶子节点不需要向下调整。第二向下调整siftDown时要先把“左右孩子中较大的那个”和父节点比较漏了边界判断容易越界。尤其是右孩子存在的前提是child 1 n。第三排序阶段堆顶和堆尾交换后堆的规模要减1但很多人忘了更新堆大小导致排完序后数组前部又被堆化了一遍。下面给一个可以直接抄的C堆排序模板大顶堆升序void siftDown(vectorint a, int n, int i) { while (i * 2 1 n) { int child i * 2 1; if (child 1 n a[child 1] a[child]) child; if (a[child] a[i]) { swap(a[i], a[child]); i child; } else { break; } } } void heapSort(vectorint a) { int n a.size(); for (int i n / 2 - 1; i 0; i--) siftDown(a, n, i); for (int i n - 1; i 0; i--) { swap(a[0], a[i]); siftDown(a, i, 0); } }很多同学会问为什么要从 n/2 - 1 开始建堆因为数组最后一个叶子节点的父节点就是 n/2 - 1从这往后的节点全是叶子节点叶子节点没有孩子不需要下沉。从最后一个非叶子节点开始自底向上依次调整就能保证每一个子树都满足堆性质。至于“冒泡排序算法c”这种题一般不会让你写完整代码而是考时间复杂度O(n^2)、稳定性稳定以及“什么时候排序次数最少”序列基本有序时。但不管哪种排序我建议都手写一遍写的时候注意内层循环的边界这部分最容易出问题。2.3 快速幂与二分数学类题目的通用套路快速幂算法也是笔试常客。计算 a^b mod m最朴素的做法是循环b次时间复杂度O(b)当b达到10^9级别时就超时了。快速幂的核心思想是二进制拆分把b拆成二进制形式通过不断平方底数来减少乘法次数时间复杂度降为O(log b)。一个实用的C实现long long quick_pow(long long a, long long b, long long m) { long long res 1 % m; a % m; while (b) { if (b 1) res res * a % m; a a * a % m; b 1; } return res; }考场上的易错点有三个第一res初始值要考虑m1的情况所以写成 1 % m第二a在进入循环前要取模否则中间结果可能爆long long第三b要用long long如果用int右移过程中遇到大数会溢出。这些细节看起来不起眼但在笔试里都是实实在在的扣分点。和快速幂常一起出现的还有二分答案法尤其是求解“最大值最小”或“最小值最大”这类最优化问题时非常管用。典型题型包括在有序数组中查找第一个不小于target的位置、分配问题、贪吃的最小速度等。二分法的核心是循环不变量在每一轮循环中答案都在区间[l, r]内然后通过mid判断答案在左半区间还是右半区间。注意边界处理时是l mid 1还是l mid这决定了循环是否会死循环。我习惯用闭区间写法while (l r)然后根据单调性决定要不要mid 1或mid - 1这样能最大程度避免死循环。贪心算法也是常考概念笔试里通常出“证明贪心选择性”或“判断能否用贪心”这类题。记住一句话贪心适用于局部最优能推出全局最优的问题。遇到区间调度、活动选择、分发饼干这类题型优先考虑贪心思路。但如果遇到背包变体、某些路径问题贪心不成立要改用动态规划。这个判断能力需要靠刷题积累。3. 机器学习与深度学习模型与调优的综合题3.1 经典模型对比从KNN到集成学习机器学习算法在热词里被反复提及包括“knn算法的应用能力包括哪三个方面”“聚类算法”“xgboot算法”“强化学习算法”。笔试选择题常考“给你一个场景让你选合适的模型”或“比较几个模型的优缺点”这类题。KNN的三个应用能力很多同学会记混。我理解的角度是第一是分类能力通过K个最近邻投票决定样本类别第二是回归能力通过K个最近邻的均值或加权均值预测连续值第三是异常检测或密度估计能力因为KNN本身基于距离度量可以衡量样本的局部密度距离远的地方密度低有可能是异常点。再比如XGBoost它属于集成学习里的Boosting家族核心思想是串行训练多个弱学习器每个弱学习器重点拟合前面所有模型的残差同时通过正则项控制模型复杂度防止过拟合。笔试如果问“XGBoost和GBDT的区别”最核心的点是XGBoost对损失函数做了二阶泰勒展开而GBDT只用了一阶负梯度XGBoost显式加了正则项XGBoost支持特征列采样并且能自动处理缺失值。这些点最好能一字不差地写出来。聚类算法也是一个高频考点。最经典的是K-Means笔试常问“K-Means的步骤”和“如何选择K”。步骤就三步初始化K个中心点把每个样本分配到最近的中心重新计算每个簇的中心重复直到收敛。选择K常用肘部法则或轮廓系数。注意K-Means对初始点敏感可能收敛到局部最优所以一般会用K-Means做初始化。这些细节在选择题里经常作为干扰项出现。3.2 损失函数与优化KL散度、ELBO与训练中的坑热词里有“kl elbo算法原理详解”。这两个概念在变分推断里非常重要笔试或面试中可能会以“简述变分自编码器VAE的原理”的形式出现。KL散度用来度量两个概率分布之间的差异公式是KL(P||Q) Σ P(x) log[P(x) / Q(x)]。它不是一个对称量即KL(P||Q)不等于KL(Q||P)所以严格来说不能叫“距离”。这个概念我建议大家理解透笔试常会设一个“对称性”的陷阱选项。ELBOEvidence Lower Bound证据下界是在最大化对数似然时得到的一个下界。推导思路是log P(x) log Σ_z P(x, z) log Σ_z Q(z) [P(x, z) / Q(z)] 利用Jensen不等式 ≥ Σ_z Q(z) log [P(x, z) / Q(z)] E_{Q(z)}[log P(x, z) - log Q(z)] ELBO同时ELBO还可以改写成 ELBO log P(x) - KL(Q(z) || P(z|x))。因为KL散度非负所以ELBO是log P(x)的下界。优化ELBO就等价于在逼近真实后验P(z|x)的同时最大化观测数据的似然。我在复习时发现很多同学能背出公式但答不出“为什么要引入Q(z)”。这里的关键是真实后验P(z|x)通常不可解所以我们用一个简单的变分分布Q(z)去近似它。让Q(z)和P(z|x)的KL散度最小但P(z|x)又不可直接计算于是绕道优化ELBO。理解了这个动机整个推导就不需要死记硬背了。3.3 深度学习在视频理解中的应用方向爱奇艺作为视频平台深度学习考题常和视频场景结合。常考的方向包括视频分类与行为识别经典网络有C3D、I3D、SlowFast。考点通常不是背网络结构而是理解“为什么用3D卷积”和“为什么要有双流结构”。3D卷积相比2D卷积多了时间维度可以同时捕捉空间和时间特征双流结构是把RGB图和光流分开处理再融合目的是把“外观”和“运动”信息解耦。目标检测与跟踪在视频帧上做检测常用Faster R-CNN、YOLO系列跟踪常用SORT、DeepSORT。笔试最常见的考法是“Faster R-CNN的RPN是什么”答案是Region Proposal Network用来生成候选框。这个不能答成“循环神经网络”。视频推荐与用户画像用深度模型做召回和排序比如DSSM、YouTube DNN召回模型。这类题目一般不会让你推公式而是考“召回和排序阶段有什么区别”答案要点是召回阶段要从千万级候选里粗筛出几百个追求高召回率排序阶段对几百个做精排追求高精度。深度学习基础概念里笔试选择题很喜欢问“以下哪个操作可以减小过拟合”答案一般是正则化、数据增强、早停、Dropout、Batch Normalization。Dropout的本质是训练时随机丢弃一部分神经元相当于训练多个子网络的集成推理时再恢复。这个回答要能写完整不能只说一句“随机丢弃神经元”。4. 工程与场景结合视频平台特有的算法考点4.1 图像处理与视频算法Sobel边缘检测、图像锐化热词里有两个图像算法“图像锐化的拉普拉斯算法”和“sobel算法”这正好是视频平台常考的点。视频里的每一帧都是图像图像处理基础是视频算法工程师的必修课。Sobel算子是一种基于离散微分的边缘检测算子它有两个3x3卷积核一个计算水平方向梯度Gx一个计算垂直方向梯度GyGx -1 0 1 -2 0 2 -1 0 1Gy -1 -2 -1 0 0 0 1 2 1拿到梯度后常用公式是 G sqrt(Gx^2 Gy^2)或者快速近似为 |Gx| |Gy|。梯度值大的地方就是图像亮度变化剧烈的地方也就是边缘。在实际工程中如果用近似公式计算的绝对值差异不大但速度更快适合实时视频处理。拉普拉斯算子做图像锐化的原理是拉普拉斯算子是二阶微分算子可以检测出图像中的灰度突变。常用的4邻域拉普拉斯核是[0 1 0; 1 -4 1; 0 1 0]8邻域版本是[1 1 1; 1 -8 1; 1 1 1]。锐化的输出图像 原图 - k * 拉普拉斯(原图)其中k是锐化强度系数。因为拉普拉斯算子输出的是二阶导数在边缘处响应很强直接在原图上减掉这部分灰度变化会变得更陡峭视觉上就更“锐利”。我实际做图像处理项目时踩过一个坑直接对整张RGB图像做拉普拉斯锐化结果彩色图像出现明显色偏。原因是三个通道被单独处理时边缘强度不一致导致颜色失真。正确做法是先转换到YUV或Lab颜色空间只对亮度通道做锐化色度通道保持不变。这样既保留色彩又提升清晰度。这个经验在笔试选择题里也可能出现问的是“如何避免彩色图像锐化后的色偏”。4.2 搜索与推荐BM25、排序算法的实际场景视频平台的两大核心业务是搜索和推荐。热词里的“bm25算法”是信息检索领域的经典打分函数笔试里出现过“简述BM25的原理”这类简答题。BM25的核心思想是一个文档如视频标题、弹幕、字幕和查询的相关性不是简单地看词频而是综合考虑词频、文档长度和逆文档频率。公式大致是score(D, Q) Σ_{i1..n} IDF(q_i) * [ f(q_i, D) * (k11) ] / [ f(q_i, D) k1 * (1 - b b * |D| / avgdl) ]参数k1控制词频的饱和程度b控制文档长度的影响。b0时完全忽略文档长度b越大文档长度惩罚越强。笔试常见的变形题是“如何设计视频搜索的排序特征”答案可以从文本相关性BM25、点击率预估、时效性、多样性四个维度展开。如果只能写三点写文本相关性、时效性、点击率就够了。排序算法在推荐系统里也有体现。热词里有“数据结构排序算法”但在推荐场景里通常不是简单的快排或堆排而是如何从候选池中选取TopN个最优结果。一般来说用最大堆或最小堆维护一个大小为N的最小堆遍历候选结果如果当前分数比堆顶大就替换堆顶并重新调整。这样时间复杂度是O(M log N)M是候选数量N是最终返回数量比全量排序快得多。这也是“堆排序”在真实业务里最常见的应用场景之一。4.3 流控与稳定PID、卡尔曼滤波在视频系统中的作用这个方向容易被忽视但视频平台其实很关注播放稳定性和资源调度。热词里有“pid算法”和“卡尔曼滤波算法”它们在视频系统里并不是空谈。PID算法比例-积分-微分控制在视频领域的典型应用是码率控制和缓冲控制。播放器希望维持一个目标缓冲时长如果实际缓冲偏离目标就按比例P、累积误差I、误差变化率D来调整下载码率或播放速度。P让系统快速反应I消除稳态误差D抑制超调。笔试里如果出开放题“如何设计自适应码率控制器”用PID思路回答是比较加分的。卡尔曼滤波在视频系统里可以做带宽预测和用户行为预测。它通过“预测-更新”两步在线性高斯噪声假设下给出均方误差最小的估计。简单说先用上一时刻的状态预测当前状态再用当前观测值修正预测。视频播放时网络带宽波动很大用卡尔曼滤波平滑带宽估计可以避免码率频繁切换提升观看体验。笔试可能会出选择题“卡尔曼滤波的两个步骤是什么”答案是预测predict和更新update也叫时间更新和测量更新。这个点不难但容易跟粒子滤波搞混。粒子滤波用于非线性、非高斯的场景通过一组带权重的粒子近似后验分布计算成本高卡尔曼滤波只适合线性高斯场景但计算快、实时性强。记住这个对比遇到选择题直接能选出来。热词里的“粒子群算法原理”和“模拟退火算法”也值得提一下。粒子群算法模拟鸟群觅食行为每个“粒子”代表一个候选解通过追踪个体最优和全局最优来更新速度和位置适合连续空间上的无梯度优化。模拟退火则模拟金属退火过程以一定概率接受更差的解从而跳出局部最优。这两类算法在笔试中常以“简述原理”或“比较优缺点”的形式出现不需要会手写完整实现但要把核心思想讲清楚。4.4 音频重采样与规则引擎容易被忽略的冷门考点热词里还出现了“音频重采样算法”和“规则引擎drools的rete算法实现原理和事实匹配过程”。这两个点相对冷门但如果简历里写了音视频处理或后端工程经验就可能被追问。音频重采样的本质是改变采样率比如从44.1kHz转到48kHz。最朴素的方法是线性插值但会产生频谱混叠音质差工程上常用带限插值先对信号做低通滤波再在目标采样率上重构采样点。笔试如果只考概念回答“重采样 插值 抗混叠滤波”这句话就够了。如果被追问“为什么需要抗混叠滤波”答案是采样率降低时高于新采样率一半的频率分量会折叠到低频部分产生失真。Rete算法是规则引擎Drools的核心匹配算法它把多个规则的条件部分构建成一个共享的网络Pattern Network Join Network利用事实在节点间传递时的缓存来避免重复计算从而高效匹配大量规则和事实。如果笔试给一段规则日志让你分析匹配过程掌握“左输入缓存、右输入缓存、终结点触发”这三个概念基本就可以应对。这类题目更多的考察工程理解力看到“网络共享”“缓存中间结果”这些关键词往Rete算法上靠就对了。5. 常见问题与排查技巧实录5.1 字符串与边界条件KMP之外的细节坑KMP这类题出错很多时候不是原理不懂而是边界条件没处理好。比如“abacaba”这个模式串用定义A算next数组时很多同学在next[5]和next[6]上出错原因是回退时不够果断。我给一个小技巧手算next数组时每次只观察前i个字符找“最大相等前后缀”找不到就写0或根据定义写对应值不要跳步去猜。写代码时把模式串的前缀和后缀“错开一位”来理解这样就不会被连续的重复字符绕晕。另外要检查字符串匹配的循环退出条件。以KMP为例主串遍历完了但模式串还没匹配完应该返回匹配失败如果模式串走完了说明匹配成功要注意返回的位置是主串下标减去模式串长度加1不要算错。字符串题里还有一个高频考点是快速幂和字符串哈希的结合比如“判断一个字符串是否包含另一个字符串的子串”这类题除了KMP还常用滚动哈希Rabin-Karp。笔试时如果被要求写代码我建议优先写KMP因为它的时间复杂度稳定O(nm)不会被哈希碰撞影响。5.2 机器学习选择题里常见的“表述陷阱”笔试选择题很喜欢用绝对化表达来挖坑。比如“增加树的深度一定可以提高模型效果”“KNN的K值越大越好”“SVM只能处理线性可分问题”这类选项基本都是错的。我在做题时的经验是看到“一定”“必须”“只能”“所有”这类词要立刻提高警惕回到定义里找反例。再比如正则化参数的坑。L1正则化更偏向产生稀疏解L2正则化会更均匀地缩小权重二者在笔试里经常对比考法通常是给你几个选项判断哪个描述正确。记住一句话L1是权重的绝对值之和带稀疏性L2是权重的平方和更稳定不会把权重压到0。如果选项里说“L2正则可以用于特征选择”那是错误的特征选择要的是稀疏性应该用L1。我整理了一个高频考点速查表方便临考前扫一眼概念核心特点常见陷阱KNN非参数、基于距离K值越大越好错需调参K-Means迭代聚类需指定K对初始点不敏感错敏感L1正则产生稀疏解L2可做特征选择错SVM最大化间隔只能处理线性可分错有核技巧Dropout训练时随机丢弃神经元训练和推理都需要丢弃错推理不丢KL散度非对称非负可当作距离错不对称5.3 时间不够怎么办取舍与检查顺序笔试时间紧张时我的策略是三层取舍先做会做的再做部分会做的最后蒙剩余题。编程题如果解法真的写不出来也要把暴力解写上并注明可优化方向至少能拿到部分分。选择题不要空着但也不要盲目跳题用“排除法 直觉”的方式选一个至少还有概率得分。最后5分钟优先检查编程题的输入输出格式、数组越界、int溢出这三类问题出现的概率远高于逻辑错误。我经历过一次因为数组越界导致全部测试用例失败的惨案从那以后每次都会花两分钟做边界检查。检查时重点看数组下标是否为负数、是否等于数组长度、循环里有没有可能死循环、递归有没有出口。如果是手写代码题还要注意代码风格和变量命名。阅卷人通常不会逐行运行而是快速浏览代码逻辑是否清晰。一个能快速被看懂的代码即使有小瑕疵也比写得一团乱麻但逻辑正确的代码得分高。这是很多实战经验不足的同学容易忽略的点。结尾在我整理这份复盘的时候回忆最深的是考场上那种“明明会但时间不够”的遗憾。后来我带过几个学弟学妹发现算法岗笔试的考察逻辑这些年其实变化不大基础题永远占比最高场景题考察的是思维方式冷门题只是用来拉开区分度。如果你手上有类似的真题建议按我上面提到的“数据结构与经典算法—机器学习与深度学习—场景工程算法”三个维度去拆解把每道题归入对应模块再针对性复习效率会高很多。再分享一个小技巧准备一个错题本不是记答案而是记录“我为什么错”。是边界没考虑是概念表述不严谨还是时间分配失误这个反思过程比刷十道新题都管用。我当时把错题按模块分类整理考前只看错题本效果比重新翻教材好得多。祝你在这一季的校招里拿到满意的offer。
返回列表