vivo算法岗笔试高频考点全解析:从KMP到粒子群算法
1. 先搞清楚笔试到底考什么vivo算法岗题型与考察逻辑1.1 2024秋招vivo算法类笔试的整体结构我投的是vivo的CV算法岗秋招笔试通知来得挺快从投递到收到笔试链接大概隔了不到一周。整套卷子90分钟题目量不大但覆盖范围相当广大致分成三块选择题、问答题、两道编程题。选择题大概10道左右考的是数据结构和机器学习基础比如给一棵二叉树让你推后序遍历、给一段快排代码问你时间复杂度、KNN的基本原理、过拟合的解决手段偶尔还会冒出一道图像滤波的题。这部分难度不高但很看基础牢不牢。问答题一般有两到三题要求用文字描述某个算法的原理。我当时碰到的题目是“简述粒子群算法的基本流程”和“KMP算法中next数组的作用”。这种题没有标准答案但阅卷的人能一眼看出你是真懂还是背概念。两到三道编程题是整场笔试的大头难度适中一道偏数据结构一道偏思维。实测下来把基础算法复习扎实的人通过率会明显高一些。1.2 算法岗笔试和互联网大厂的区别很多同学习惯拿互联网大厂的题库去准备vivo这种做法有个问题大厂笔试特别喜欢考高难度动态规划和复杂状态压缩而vivo的算法岗更偏向工程实践和行业场景。手机厂商的算法团队平时做什么相机影像算法、音频降噪、AI端侧部署、搜索推荐、电源管理里的控制算法这些都是实打实要和硬件打交道的方向。因此笔试选用的算法题目也更倾向于“基础但实用”。比如热词里出现的BM25、PID、SOBEL、拉普拉斯锐化这些看起来杂七杂八的算法背后正好对应了搜索排序、电源控制、图像处理这些手机厂商业务场景。我在复习时一开始只觉得这些东西零散后来才意识到这些就是vivo算法岗笔试真正想考察的核心能力基础算法原理扎实、能理解工程算法场景、会动手写代码。1.3 时间分配策略90分钟怎么用根据我的实操经验笔试的时间分配建议这样选择题最多25分钟问答题25分钟剩余40分钟留给编程题。编程题宁可做对一道、留下一道空着也不要两道都写了一半。vivo的在线笔试系统通常支持本地IDE编译但也不排除部分场次只提供网页编辑器所以平时就要练手写代码的熟练度。选择里如果卡壳超过2分钟先随便选一个并标记回头再看。问答题要写核心流程和关键公式尤其是类似“粒子群算法的速度更新公式”这种硬核内容写出来就是加分项。编程题先读清楚输入范围和边界条件再动手。我见过太多人一上来就写写到一半发现漏了空数组的情况当场崩溃。2. 高频考点精讲从字符串到机器学习这些算法必须滚瓜烂熟2.1 字符串算法KMP的next数组手撕推导必须熟练KMP算法在vivo笔试中出现的频率不低。模式串的next数组计算是必考基本功值得反复练习直到能闭着眼写出代码。以热词里的模式串 pabacaba为例我们计算它的next数组这里采用0索引、next[i]表示前i个字符构成的子串中最长相等前后缀的长度next[0] 0单个字符没有前后缀长度为0。i1子串ab前缀a后缀b不相等next[1]0。i2子串aba前缀a等于后缀a长度1同时ab不等于ba所以next[2]1。i3子串abac前缀a对应后缀c不相等前缀ab对应后缀ac不相等继续往前找next[3]0。i4子串abaca前缀a等于后缀a长度1next[4]1。i5子串abacab前缀ab等于后缀ab长度2next[5]2。i6子串abacaba前缀aba等于后缀aba长度3next[6]3。最终next数组就是 {0, 0, 1, 0, 1, 2, 3}。有些教材把next定义为失配跳转位置那会在部分场景上偏移一位考试时要看清题目定义避免踩坑。vectorint buildNext(const string p) { int m p.size(); vectorint next(m, 0); int j 0; for (int i 1; i m; i) { while (j 0 p[i] ! p[j]) j next[j - 1]; if (p[i] p[j]) j; next[i] j; } return next; }这段代码的精髓在于while循环里的回退。匹配失败时不必从头开始而是利用已经计算好的next数组跳回到上一个可能的匹配位置。KMP的时间复杂度是O(nm)空间复杂度O(m)比暴力匹配稳定得多。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(n)稳定堆排序O(n log n)O(n log n)O(1)不稳定快排的平均性能最好但最坏退化到O(n²)。如果笔试问“数据基本有序时用哪个排序最好”插入排序是标准答案。归并排序虽然需要额外空间但胜在稳定适合外部排序。堆排序在需要取TopK的场景里很实用。刷题时我习惯背熟这些结论再配合一两道手写排序题练手笔试基本不会失分。2.3 图论与动态规划Dijkstra、贪心、DP怎么区分Dijkstra算法是处理单源最短路径的经典算法。它的基本思想是维护一个dist数组每次从未访问的节点中选一个距离最小的节点然后更新它相邻节点的距离。朴素写法时间复杂度O(V²)用优先队列优化后可以降到O(E log V)。不过要注意Dijkstra不能处理负权边。笔试里如果遇到带负权的图则要考虑Bellman-Ford或SPFA。我记得有一道模拟题真的很坑图的权值都是正数但问的是最长路径很多人条件反射就套Dijkstra结果全错。最长路径在有环图中是NP-Hard不能用Dijkstra直接改这点一定要记住。动态规划和贪心的区别也是高频问答题。贪心是每步做局部最优选择且不回头DP则是枚举所有状态并记录最优子结构。经典例子找零钱问题如果硬币面额是1、5、11要找15元贪心会先选11再选4个1一共5枚但最优解是3个5共3枚。这就是贪心失效的场景。笔试中遇到这种问题一定要先判断贪心是否能证明正确性否则就老老实实写DP。2.4 群智能与搜索优化粒子群、模拟退火、剪枝粒子群算法在vivo笔试中出现的概率很高因为它在图像匹配、相机参数标定等场景中很常用。粒子群模拟鸟群觅食行为每个粒子有位置和速度迭代更新时参考个体历史最优pbest和全局历史最优gbest。核心更新公式v[i] w * v[i] c1 * r1 * (pbest[i] - x[i]) c2 * r2 * (gbest - x[i])x[i] x[i] v[i]其中w是惯性权重c1、c2是学习因子r1、r2是0到1之间的随机数。笔试如果考简答把公式写出来再说明初始化和迭代终止条件基本就能拿满分。如果考代码不需要写得特别复杂画出基本框架就行。模拟退火和剪枝算法也值得准备。模拟退火的核心是Metropolis准则以一定概率接受更差的解避免陷入局部最优。剪枝在搜索树中很常见比如Alpha-Beta剪枝、DFS中的可行性剪枝和最优性剪枝。这些算法直接考代码的概率不大但会在问答题中以“如何优化搜索效率”的形式出现。2.5 机器学习与深度学习KNN、聚类、强化学习都要懂一些vivo算法岗笔试对机器学习的考察偏基础。KNN是重点它的应用能力可以概括为三方面分类、回归和异常检测。KNN分类通过多数投票决定类别回归通过取k近邻均值预测连续值异常检测则是利用样本到近邻的距离来判断离群点。KNN没有显式训练过程属于懒惰学习但预测时计算量大样本维度高了还会面临“维度灾难”。聚类的常见算法也要能说出区别K-Means适合球形簇DBSCAN能发现任意形状的簇且能处理噪声层次聚类可以输出树状图。我遇到过一道选择题给了一张散点图问适合用什么聚类算法答案就是DBSCAN因为图里有两个弧形簇和一堆噪声点。深度学习部分CNN的卷积层、池化层、全连接层的基本作用要能讲清楚。RNN处理序列数据LSTM解决了RNN的长依赖问题。2024年的笔试越来越喜欢问大模型和端侧部署相关的问题比如模型量化、剪枝蒸馏这些最好也了解一点。强化学习的核心要素是状态、动作、奖励和策略知道马尔可夫决策过程和Q-Learning的基本流程就够了。2.6 工程算法速览快速幂、BM25、PID、SOBEL、Rete这块内容比较杂但确实在各个行业的笔试里都出现过。快速幂是必须拿分的题不要只会背模板要理解二进制分解原理。BM25是搜索引擎常用的文本相关性算法核心是词频、逆文档频率和文档长度归一化的结合。PID控制器在电源管理、电机控制里非常重要基本原理是根据偏差的比例、积分、微分三项来计算输出。增量式PID的公式也要记一下它计算的是控制量的增量适合执行器带记忆的场合。SOBEL算子和拉普拉斯算子都是图像锐化、边缘检测的基础算子。SOBEL通过对图像做水平和垂直方向的卷积计算梯度幅值来检测边缘拉普拉斯是二阶微分算子对噪声敏感实际用的时候通常会先做高斯平滑。Drools规则引擎里的Rete算法更偏后端但笔试问算法匹配原理时只要能说出“构建规则网络、共享条件节点、事实在节点间传递匹配”这个核心思路就够了。3. 编程题实战套路这几道题吃透笔试稳了一半3.1 手写快速幂递归和迭代两种写法都要会快速幂在很多题目里是优化关键比如计算a的b次方再对mod取模。核心思想是把指数b拆成二进制利用a^b a^(2^k1) * a^(2^k2) * ...从而把时间复杂度从O(b)降到O(log b)。递归写法long long powMod(long long a, long long b, long long mod) { if (b 0) return 1 % mod; long long half powMod(a, b / 2, mod); half half * half % mod; if (b % 2 1) half half * (a % mod) % mod; return half; }迭代写法long long powMod(long long a, long long b, long long mod) { long long res 1 % mod; a % mod; while (b 0) { if (b 1) res res * a % mod; a a * a % mod; b 1; } return res; }常见错误有三个一是忘记处理b为0的情况二是模运算时没有先对a取模导致int溢出三是递归写法里把“b是奇数”的判断写成了b % 2 0结果全错。笔试现场如果时间紧建议直接默写迭代版因为它不会爆栈也不用担心递归过深。3.2 手写KMP完整实现从next数组到匹配过程KMP不是背代码就行的算法要能边写边解释。这里给出一份完整的KMP匹配函数int kmp(const string text, const string pattern) { vectorint next buildNext(pattern); int n text.size(), m pattern.size(); int j 0; for (int i 0; i n; i) { while (j 0 text[i] ! pattern[j]) j next[j - 1]; if (text[i] pattern[j]) j; if (j m) return i - m 1; } return -1; }我笔试时曾在这道题上栽过跟头原因是next数组的构建用的是“最长相等前后缀长度”而匹配回退时用的是next[j-1]两边定义没统一。所以你一定要确认自己的代码里buildNext返回的到底是什么含义并保持一致。3.3 现场模拟题旋转数组最小值、二叉树层序遍历我把两道代表性题目放在一起模拟一下。旋转数组最小值一个原本升序排列的数组在某个点做了旋转比如[4,5,6,7,0,1,2]要求找到最小值。最优解是二分查找时间复杂度O(log n)。如果中间值小于右边界说明最小值在左半部分包括mid本身否则在右半部分。int findMin(vectorint nums) { int left 0, right nums.size() - 1; while (left right) { int mid left (right - left) / 2; if (nums[mid] nums[right]) left mid 1; else right mid; } return nums[left]; }二叉树层序遍历用队列做BFS注意每层要先记录当前队列大小再循环弹出否则无法区分层级。vectorvectorint levelOrder(TreeNode* root) { vectorvectorint res; if (!root) return res; queueTreeNode* q; q.push(root); while (!q.empty()) { int sz q.size(); vectorint level; for (int i 0; i sz; i) { TreeNode* node q.front(); q.pop(); level.push_back(node-val); if (node-left) q.push(node-left); if (node-right) q.push(node-right); } res.push_back(level); } return res; }这种题难度不大但很考验代码基本功。我建议你把它们作为“必会题”反复练习直到10分钟内能完整写出来。4. 避坑清单与高效复习路线实战踩坑后的经验总结4.1 笔试现场最容易踩的坑第一选择题乱用“想当然”。比如排序算法稳定性很多同学凭直觉以为快排是稳定的实际上快排的partition过程中会交换相等元素是不稳定的。这种题错一次就记住了但笔试现场可没有让你错第二次的机会。第二问答题只写结论不写过程。我见过有人回答“KMP算法是通过预处理模式串来加速匹配”然后就没有然后了。这样等于没答。至少要把next数组的定义写出来再写匹配过程的基本步骤。笔试阅卷是按点给分多写一个公式多拿一分。第三编程题不处理边界条件。字符串匹配题没考虑空串二分题没处理数组长度为1树题没处理空树。这些都是送分题变成送命题的典型。写代码前先把输入范围读一遍尤其是0、负数、极大值这些边界。另外有个小提醒很多同学平时接触vivo手机刷机、adb调试、fastboot指令包对手机厂商的工程工具很熟悉但算法岗笔试不考这些。不要把复习时间浪费在系统工具和刷机指令上哪怕你对adb失效问题颇有心得笔试它也不加分。刷题才是算法岗笔试的王道。4.2 春招秋招通用的四轮复习路线第一轮数据结构基础数组、链表、栈、队列、哈希表、二叉树、堆、图。目标是能手动实现二叉树的遍历、链表反转、用两个栈模拟队列这些是后续所有算法的地基。第二轮算法思想专项二分查找、双指针、滑动窗口、DFS、BFS、动态规划、贪心、回溯。这里推荐按专题刷题不要乱序刷否则很难形成体系。第三轮高频进阶算法KMP、快速幂、Dijkstra、并查集、Trie树、拓扑排序。这些算法技巧性强笔试也喜欢考属于“练过就会没练就废”的典型。第四轮行业场景拓展如果你是投vivo这类手机厂商尽量把图像算法SOBEL、拉普拉斯锐化、音频算法重采样、搜索排序算法BM25、控制算法PID都过一遍。不需要写完整实现能理解原理、写出公式或描述流程即可。4.3 常见报错与系统问题速查表报错类型可能原因处理建议TLE超时暴力解法数据规模太大换二分、哈希、双指针或DP优化MLE超内存数组开太大或使用了递归栈改为滚动数组减少辅助空间RE运行时错误数组越界、空指针、除零检查循环边界和输入极端情况WA答案错误逻辑或边界条件有误构造小样例手动跑一遍加printf调试PE格式错误多输出了空格、换行等严格按题目输出格式检查笔试系统偶尔也会出幺蛾子。我在某次模拟测试时发现明明本机跑得好好的代码提交上去就是编译报错。后来发现是没选对编程语言版本或者漏写了头文件。这里建议提交前务必检查语言版本和头文件像#include bits/stdc.h这种写法虽然方便但在部分在线编译器上可能不支持最好老老实实包含具体头文件。4.4 关于复习资料与心态的实操心得资料方面不需要贪多。一本《算法竞赛入门经典》加一个在线刷题平台就够关键是把做过的题反复总结。我习惯每道题做一个“错因记录”比如“忘记判断空队列”、“取模溢出”、“字符串下标越界”笔试前翻一遍错题本效果比刷十道新题还好。心态也是重要变量。vivo笔试虽然覆盖广但难度总体友好只要平时多练不用担心被某道偏题卡死。我考试时遇到一道陌生问答题当时有点慌后来想起复习过的粒子群算法框架类比着写下来居然也拿了不少分。笔试考的不只是你会不会还有你面对不会的问题时能不能冷静地把已知的东西组织起来。我在实际准备过程中最大的体会是这类笔试拼的从来不是奇技淫巧而是稳定的基础输出。能把KMP的next数组推导清楚、能默写出快速幂、能讲明白粒子群的速度更新公式再配合一轮系统的刷题训练通过笔试的把握就会大很多。如果你正在准备下一场笔试最后再分享一个小技巧复习时把每个高频算法都写在一张白纸上从原理、公式、复杂度到适用场景像面试一样默写一遍。能默写出来的才是真会翻着书觉得“我懂了”的那种大概率一到考场就露馅。