ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

vivo校招在线编程笔试A卷:题型解析与实战避坑指南

vivo校招在线编程笔试A卷:题型解析与实战避坑指南 每年九、十月份各大厂的校招笔试就像一场全国范围内的打怪升级“vivo 2020届校招在线编程笔试A卷”这个名字在当年牛客网和知乎上被刷了不少存在感。我自己也参加过同一届的线上笔试当时用的就是标准的在线编程评测系统题目风格和牛客网真题卷高度接近做完之后最大的感受是它考的不是你会不会写某道题的答案而是你在有限时间内能不能稳定地把一个工程问题拆开、建模、实现、调通。这篇内容就围绕这套A卷展开把当时大家在笔试群里讨论过的高频考点、在线编程平台的评测机制、还有我踩过的坑一并整理出来。适合正在准备校招笔试的应届生、想跳槽去终端厂商做技术岗的开发者以及单纯想搞懂“在线编程笔试到底怎么筛人”的在校生。哪怕你还没到求职季提前理解这套玩法也不亏。1. 校招在线编程笔试到底在考什么1.1 vivo这类终端厂商的笔试有什么特点先说一个容易被忽略的事实vivo虽然是手机厂商但校招笔试的在线编程题并不偏硬件反而非常偏基础算法和代码实现。A卷的题目范围大体集中在数组、字符串、模拟、动态规划、贪心这几类偶尔会有一道和图论沾边的题。这是因为校招岗位面向的是软件研发、算法、测试等方向笔试的目的不是筛选谁刷题多而是看你能不能把问题抽象成数据结构与算法模型再用代码实现出来。另一个特点是这套题整体难度在中档偏上前一两道相对友好后面的题会拉开差距。我当时做题的顺序是先扫一遍全部题目把第一道模拟题和一道字符串处理题做掉再啃动态规划最后留时间处理最难的那道。这个策略在AC率和心态管理上都很重要。和互联网大厂动辄四道题、每道题都要最优解的“地狱模式”相比vivo A卷更看重稳定输出的能力。就算你不会特别高级的算法只要把基础题做扎实、把边界条件处理好也能拿到不错的分数。它是在筛选能干活、逻辑清楚的人不是筛选竞赛选手。1.2 A卷的常见考核维度与题型分布从当年线上笔试的实际反馈来看A卷大体可以归纳为以下四类考核维度本人记忆力有限没法把每道原题逐字复现但下面这些题型和考法是大家在笔试群里复盘时公认的高频方向非常具有代表性。题型方向常见考法核心知识点模拟题按规则模拟多轮流程比如排队、洗牌、机器人走路状态机、循环终止条件、数据结构选择字符串处理单词反转、子串匹配、括号匹配API熟练度、边界处理、栈的使用动态规划背包变体、最长子序列、路径计数状态定义、转移方程、空间优化贪心与排序活动安排、区间合并、最小差值贪心证明、排序规则设计这里想提醒一句模拟题虽然看起来“简单”但它反而是失分重灾区。原因是模拟题往往细节多循环条件稍微写错一个等号或者没有搞清楚“先判断再执行”还是“先执行再判断”整道题就会挂掉。在线编程没有人工看代码的过程评测机只认输出所以你必须靠自己在本地把各种情况测到位。1.3 为什么公司宁愿用在线编程笔试来筛人很多同学会问我项目经历不错简历上写了挺多东西为什么还要做在线编程笔试其实原因很现实。简历上的项目经历可以包装但代码能力很难在短时间内伪装。在线编程笔试提供了一个统一、客观的筛选维度不管你是985还是普通双非同样一套题同样的时限同样的评测标准代码一跑就知道水平。更重要的是在线编程笔试测评的是“你在有压力的环境下能不能搞定一个明确的需求”这和实际工作非常像。工作里经常会遇到一个需求边界条件模糊、数据量大、要和其他模块对接而你需要在截止时间前给出可用的实现。笔试现场你也会面临类似的情况——时间有限、样例有限、还没有人帮你排查全凭你平时积累的代码直觉和工程习惯。这就是为什么公司愿意在校招流程里保留在线编程笔试这个环节它筛掉的不是“不会刷题”的人而是“遇到问题项目就束手无策”的人。2. 典型题型拆解从审题到AC的完整思路2.1 数组与模拟类题目先把流程理顺再写代码数组和模拟类题目通常是A卷的前两题也是大家最容易犯“眼高手低”错误的题。这类题不会涉及太高深的算法但会设计出一套规则要求你模拟一个过程。比如一个典型的考法是给定一个初始数组每一轮按规则生成新数组重复若干轮后输出结果。遇到这种题我通常建议先不写代码先在草稿纸上把一轮操作的手动过程推演一遍。搞清楚几个关键问题这一轮操作是原地修改还是生成新的数组每一轮之间有没有状态残留循环结束条件是达到指定轮数还是数据收敛以“生成新数组”为例如果直接在原数组上修改可能会影响接下来的计算。正确做法是开辟一个新数组存储本轮结果然后整体覆盖或交替使用两个数组。这种“空间换正确性”的手法虽然会多占用一份内存但在笔试场景下数据规模通常不会大到不可接受换取正确性是完全值得的。另外模拟题还需要特别注意下标边界。很多题目从1开始计数但数组索引从0开始这种换算最容易出错。我的习惯是在代码里保留题目原始下标含义定义变量名时直接带上语义比如roundIndex、currentValue不要让代码变成一堆i、j、k否则写着写着就晕了。2.2 字符串处理类题目注意边界和语言API的差异字符串处理题是A卷的常客但这里的“常客”不等于“送分”。很多字符串题看起来简单实际上一堆边界条件没有处理好样例通过率就上不去。举一个高频的例子反转句子中的单词顺序比如输入hello world vivo输出vivo world hello。这个题如果不允许使用额外的split库函数就需要自己遍历字符串按空格切分单词再倒序拼接。这类题最容易踩的坑有三个字符串开头、结尾、中间有多个连续空格如何处理逆序之后单词之间的空格数量要不要保持一致统一用空格分隔时收尾是否多了一个空格如果使用C的istringstream连续空格会被自动忽略这在很多题目里没问题但如果题目要求保留原始空格格式就必须自己手动解析。用Java的话String.split在处理 时会有前导空串问题需要用正则或先trim。用Python则要记住split()和split( )行为完全不同前者会自动合并连续空白后者不会。另外一个容易被忽略的点是字符串匹配类题目的复杂度。如果在长度为n的文本里查m个模式串用暴力匹配是O(n*m)笔试数据一大就会超时。这时就得考虑KMP或者前缀哈希。很多同学总觉得笔试考KMP不太可能但实际上这类题目只要把数据规模稍微调大暴力算法就会TLE逼着你去用更优的解法。2.3 动态规划与状态压缩笔试拉开差距的核心动态规划在vivo A卷里几乎是必考的。它的题型非常广泛常见的有背包问题、最长上升子序列、编辑距离、矩阵路径数等。这类题目的难点在于你能不能用数学语言把问题描述成“状态”和“转移”而不是靠直觉硬写。举个例子一个经典变体是有一个容量为W的背包有若干个物品每个物品有体积和价值问如何装能获得最大价值。基础版本很简单但如果加上“每个物品只能选一次”或“能选无限次”状态转移方程就完全不同。一位一维数组优化的时候背包问题的内层循环是正序遍历还是倒序遍历这是很多人的失分点。这里我分享一个实际处理动态规划题的小技巧在写代码之前先在注释里把状态定义和转移方程写出来再动代码。比如// dp[i][j] 表示前i个物品容量为j时的最大价值 // 第i个物品不选dp[i][j] dp[i-1][j] // 第i个物品选dp[i][j] max(dp[i][j], dp[i-1][j - weight[i]] value[i])把这两行写在代码里哪怕写到后面思路混乱了也能靠注释快速拉回主线而且如果最后要跟面试官讲思路这份代码就是最好的讲解稿。这种习惯我在笔试复盘后一直保留到了实际项目里写复杂状态机也很有用。对于压轴级别的动态规划题通常需要用到状态压缩、滚动数组或数据结构优化。如果你的目标是进入下一轮面试建议把常见的状态压缩套路提前过一遍理解“状态用二进制位表示”的思想比如旅行商问题的经典解法。虽然不一定会考到但这类题一旦出现往往是区分度最高的题。2.4 图论与贪心高频但不是必考的补充点图论在vivo A卷里的出现频率不算最高但一旦出现常见考法是最短路径、最小生成树、拓扑排序和并查集。很多同学一看到图就慌了觉得要写一堆复杂的邻接表和堆优化。实际上笔试里的图论题数据规模通常不会特别大用邻接矩阵加Floyd或者朴素Dijkstra也能过关键在于你有没有快速判断出“这是图论题”的敏锐度。我记得身边有朋友在笔试时遇到一道题表面上是给出一堆城市之间的道路和费用求从起点到终点的最小花费。这题的本质就是单源最短路径但他想了两分钟没反应过来直接当成模拟题去写结果越写越复杂最后超时。所以刷题的时候一定要锻炼“题型敏感度”看到“最小代价”“最短时间”“最少步数”这些关键词第一反应就应该是图论算法。贪心算法在A卷里更偏向于作为一道题目的子问题出现比如区间调度、按某个规则排序后取最优。这里要强调一点贪心算法看起来简单但必须能证明它的正确性否则笔试里很容易画蛇添足。最简单可靠的证明方法就是“交换论证法”——假设最优解和贪心解在某个位置不同通过交换元素证明贪心解不会比最优解差。哪怕你在笔试现场不写证明心里也得有数否则换个数据就过不去。3. 在线编程环境的实战操作细节3.1 常见笔试平台的输入输出模板在线编程笔试和本地IDE写代码最大的差异就是输入输出。你不需要处理文件读写也不需要考虑用户交互评测系统会把数据通过标准输入传给你的程序你只需要把正确结果输出到标准输出。听起来很简单但每年笔试都有不少人因为输入输出格式处理不对而挂掉。这里我整理几套常用的输入输出模板不同平台比如牛客网、赛码网要求差异不大但你要确保自己能默写不漏C 读入未知数量的整数#include bits/stdc.h using namespace std; int main() { int x; while (cin x) { // 处理每一个整数 } return 0; }Java 读取一整行再解析import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc new Scanner(System.in); while (sc.hasNextInt()) { int n sc.nextInt(); // 处理数据 } } }Python 快速读入大量数据import sys data sys.stdin.read().strip().split() # 然后按顺序解析 data 列表中的元素如果你平时主要用IDE练题忽略了标准输入输出的处理那在笔试开始前一定花一点时间把模板准备好。很多在线编程平台第一题就是让你读入若干个数字并求和这种“送分题”如果因为读取失败只过了一部分样例心态很容易崩。3.2 时间分配与提交策略在线编程笔试的时间通常是一个半小时到两个小时题量在3到4道之间。很多人失败不是因为不会做而是因为时间分配不合理在前面的题上死磕太久后面的题连看都没看一眼。我建议的通用策略是前5分钟先把所有题通读一遍在草稿纸上记下每道题的难度判断和可能的算法方向。然后按以下优先级去做先做自己最擅长、思路最清晰的题哪怕它在题目列表里不是第一题。对于没思路的题先跳过别浪费超过15分钟。做完所有能拿分的题之后再回来啃难题。每道题提交之前先在本地测试几组边界数据比如空数组、只有一个元素、最大值、最小值。在线评测系统通常支持多次提交但部分平台会因为你频繁提交失败而扣分。稳妥起见除非完全确定否则不要每改一行就提交一次。先在本地把所有想到的测试用例跑完再一次性提交。3.3 本地调试与在线评测的差异处理本地跑得好好的代码一提交上去就只对了一部分样例这种情况在笔试里太常见了。原因往往不是算法出了问题而是没有考虑多组测试用例的处理方式。在线评测平台有两种常见的评测方式一种是单组测试用例题目输入里只有一组数据另一种是多组测试用例程序需要循环读取直到输入结束。很多本地IDE的调试习惯是先给定一组输入程序跑完就退出但到了在线评测平台上就不行了。如果你不确定题目是多组还是单组最安全的方式是写成循环读取的格式这样无论是单组还是多组都能适配。从结果上看按循环读取方式实现的代码在单组输入下也能正常输出不会影响正确性。还有一个常见差异是输出格式。在线评测系统通常只比对输出内容不关心你代码里是否有额外输出但如果你在本地调试时打印了中间变量又没有删掉提交上去就会导致“答案错误”或“格式错误”。建议笔试时把所有调试输出用注释包起来或者写一个调试宏在评测时自动关闭。4. 实操过程中踩过的坑和排查方法4.1 边界条件与数组越界数组越界是C/C选手最常犯的错误而且越界了并不一定崩溃很多时候程序会“恰好”跑出正确结果直到你换了一组测试数据才暴露问题。这类问题排查起来非常痛苦因为错误结果可能出现在程序的后面阶段而不是越界发生的那一行。我维护自己代码的常用方法是每次在访问数组之前先用断言或者条件判断确保下标在合法范围。比如if (idx 0 || idx n) { // 打印日志排查逻辑错误 continue; }在笔试场景下这段代码可以帮你快速定位问题而且因为你输出的内容不包含调试信息最终提交前要记得清理。对于Java和Python越界会直接抛出异常所以这类问题更多出现在C代码中千万不能掉以轻心。另外一个容易被忽略的边界是int范围。题目中给出10万级别的数据量时很多中间结果可能超过2的31次方减1。使用 long long或Python的默认大整数能省去很多麻烦在笔试里不用刻意追求空间上的极致节省数据正确永远是第一优先级。4.2 大数溢出与数据类型选择数据溢出这个坑可以说是我笔试过程中踩得最疼的一次。有一道题数据范围看似不大单个数字在10的9次方以内但状态转移时需要两个数相加结果就超过了int的表示范围。当时本地测试用的小样例全部正常一提交就出现连续几个用例答案错误。后来对比输出才发现是负数才意识到是溢出。自此之后只要看到题目中的数字大于10的5次方我就会优先使用64位整数类型。C用long longJava用longPython则不用担心普通整型溢出但要小心浮点除法带来的精度问题。在笔试现场溢出问题一旦出现调试成本极高远远不如一开始就选对类型划算。4.3 超时问题与复杂度估算超时是另一种让人摸不着头脑的失败方式。代码跑了很久没结束评测系统直接判超时你不会拿到任何有效输出。面对超时最需要的是快速估算复杂度你的算法在最坏情况下运行多少次操作1秒内通常能跑大约5乘10的7次方到10的8次方次基础运算超过这个数量级就很可能超时。所以每道题动手写之前应该先看一眼数据范围脑算一下自己打算用的算法的复杂度是否在可接受范围内。比如数据范围是10的5次方两层循环就是10的10次方必然超时这时候必须想O(n log n)或O(n)的算法。如果你对复杂度没有概念笔试现场会非常吃亏因为你代码写完了才发现跑不动等于白写。这时候就需要掌握常见的优化思路桶排序代替排序、前缀和代替区间重复计算、二分查找代替线性扫描、记忆化搜索代替重复递归等。这些优化技巧并不难关键是在平时刷题时养成“写代码前先估算复杂度”的习惯。4.4 内存使用与多组用例处理有些笔试平台会限制运行内存通常在256MB或512MB。如果你的代码开辟了过大的二维数组比如int dp[10001][10001]那就是约400MB直接内存超限。对于这种场景要么把数组改成vector并配合动态分配要么使用滚动数组优化空间。例如经典背包问题里的空间优化vectorint dp(W 1, 0); for (int i 1; i n; i) { for (int j W; j weight[i]; j--) { dp[j] max(dp[j], dp[j - weight[i]] value[i]); } }这里把二维数组压缩成一维关键在于内层循环要倒序遍历防止同一个物品被重复使用。这种优化不仅是内存层面的也是很多动态规划题目的标准写法值得刻意练习。多组用例的处理也很容易出错。有的题目输入会先给一个T表示有 T 组测试数据你必须读取 T 之后循环处理。有的题目不给 T而是以文件结束符为终止标识。如果把二者混为一谈就会导致读取次数多了或少了最终结果自然错误。我的做法是看到题面描述里出现“第一行一个整数T表示测试数据组数”就明确写一个for (int t 0; t T; t)如果不确定就用while循环读取兼容性更强。5. 笔试结束后如何复盘并衔接面试5.1 从笔试结果反推薄弱点很多人笔试一结束就去对答案、查分数然后就不管了。我强烈建议做一次系统复盘因为笔试暴露的问题在后续面试里很可能还会被问到。复盘时从三个方向入手算法功底有没有因为某个算法不熟悉导致题目没做出来比如遇到动态规划完全没有思路说明状态定义这块需要补。代码实现有没有思路正确但代码写错的题这通常是边界处理、类型选择、输入输出格式的问题。时间管理有没有因为时间不够而没来得及看的题这说明前面的题耗时太长需要加强做题速度和策略。复盘不是简单把题重做一遍而是去对比参考解法和你自己解法的差距。如果参考解法用了更简洁的数据结构那说明你对 STL 或 Python 内置库还不够熟悉如果参考解法有额外的边界判断那说明你的逻辑不够严密。这些问题在面试手撕代码环节都会再次暴露。拿我自己来说当年A卷里有一道动态规划题我没做出来复盘时才发现问题出在状态定义上我用二维数组记录“当前值”但参考解法用一维数组加一个前缀最大值就搞定了。这个差距让我认识到不仅要把题做对还要尝试找到更优的设计这种思路在后来面试中帮了我大忙。5.2 把笔试代码改造成可讲的面试项目多数人不知道的是笔试里做出来的题目可以被改造成面试中手撕代码的素材。比如你在笔试中实现过一个“按规则模拟多轮流程”的题你在面试中就可以讲自己如何处理复杂流程的状态管理、如何设计数据结构来减少遍历次数、如何对边界条件做异常保护。这些问题比背一个八股答案有说服力得多。具体操作建议是笔试结束后把每道自己AC或部分AC的题整理到自己的代码仓库里注释里写清楚思路、时间复杂度和易错点。面试前把这些题重新写一遍不看原来的代码只凭注释里的思路去复现。这个过程能有效检验你是不是真的掌握了解法而不是当时刚好灵光乍现。如果你的简历上写了“熟悉算法与数据结构”面试官很可能要求现场手写代码这时候拿笔试真题练手比随机刷题更有效。因为你已经知道这套题的考察重点和风格能在短时间内快速调用对应算法真正进入面试时会更从容。另外笔试中发现的快速输入输出、复杂度估算、数组越界检查这些工程习惯在面试手撕代码时同样重要。你可以在面试时主动说出“这道题数据范围较大我选择用 long long”或“这里使用滚动数组优化空间”会让面试官觉得你有工程意识而不只是会写算法题。最后分享一个我个人的小习惯每次在线编程笔试结束后不管成绩如何我都会写一段几十字的心得记录这次笔试遇到的问题和当时的心态。攒了几场之后回头看能明显看到自己的进步曲线。校招季很长笔试不止一场别让一次失败影响后面的节奏把每一场笔试当成下一次的预演会轻松很多。
返回列表