拼多多2018校招的技术笔试,在当年可以说是“画风清奇”的存在。别的公司还在出“反转链表”“求子数组最大和”这种经典题型时,拼多多直接扔出了一堆和业务场景强相关的应用题,比如多多的拼团逻辑、优惠券计算、物流路径规划。我当年刷这套题的时候,第一反应是“这考的真是算法吗”,后来做多了才明白,它考的是“用工程思维解决真实业务问题”的能力。这份题汇总在求职圈流传了很久,几乎成了准备电商类公司笔试的必刷清单。
这篇文章不打算把每道题都贴一遍完整代码,那样篇幅太长,而且网上已经有很多现成答案。我更想站在一个过来人的角度,把这套题里反复出现的题型、背后的知识点、容易踩的坑,以及当时我们几个一起刷题的同学总结出来的答题策略,完整地拆给你看。如果你正在准备大厂校招,尤其是电商、交易、物流方向的技术岗,这篇文章应该能帮你少走不少弯路。
1. 内容整体设计与思路拆解
1.1 这套题到底在考什么
先给没做过这套题的朋友扫个盲。拼多多2018校招编程题汇总,网上能搜到的大概有十来道,覆盖了数组操作、字符串处理、动态规划、贪心算法、图的遍历、二叉树这几个经典板块。但它的“皮”和传统ACM题完全不同——它把算法包装在了一个个电商场景里。
比如有一道题是“多多君在小区门口开了一家水果店,每天要配送水果到各个楼栋,给定每个楼栋的需求量和距离,求最短配送路径”。这题剥掉外壳,核心其实是图论里的最短路径或旅行商问题的简化版。再比如有一道和“优惠券叠加”有关的题,本质上是一个区间覆盖或背包问题的变体。
我当年第一次看到这些题,最大的感受是:题目描述特别长,信息密度特别高,如果不快速提取关键条件,很容易被绕进去。而且很多题的时间复杂度约束很紧,O(n^2)都不一定稳过,必须想清楚再动手。
为什么拼多多要这么出题?我个人的理解是,校招笔试不是单纯筛“会不会写代码”,而是要筛“能不能把模糊的业务描述转化成清晰的算法模型”。你将来进公司要面对的需求,绝大多数都不是“给你一个数组,求最大值”这种句式,而是“用户领了一张满100减20的券,又参加了一个秒杀活动,结算时系统该怎么算钱”。能快速识别出“哦,这是背包问题”或“哦,这是区间DP”,比单纯会背模板重要得多。
1.2 准备这套题的合理路径
如果你拿到这套题,我不建议按顺序从第一道刷到最后一道。更高效的做法是先把题目按考点归类,然后集中突破。
我当时的分类方法是这样的:
- 纯考基础功的:数组遍历、字符串匹配、排序,这类题必须全对,不能丢分。
- 考算法模型的:动态规划(背包、区间DP)、贪心、DFS/BFS、最短路径,这类题占大头,需要重点练思路。
- 考代码实现细节的:大数运算、高精度、边界条件处理,这类题不难但特别容易在细节上翻车。
分类之后,你会发现这套题的核心难点就两个:一是从长题干里抽取出数学/算法模型,二是在限定时间内写出无Bug的代码。这两件事都需要刻意练习。
另外说一句,这套题虽然叫2018校招题,但现在拿来练手完全不过时。因为大厂笔试的风格有很强的延续性,现在很多公司出的题,依然能看到当年那套题的影子。尤其是“场景包装”这个思路,几乎是电商系公司出题的标准范式。
2. 高频考点与核心知识点拆解
2.1 贪心算法:看上去简单,证明才是关键
拼多多这套题里,贪心算法出现频率很高,而且往往是那种“你觉得你对了,其实你错了”的题。举一个典型的例子:多多的货物装车问题——有一批货物,每件有重量和价值,卡车有载重上限,问怎么装能让总价值最大。很多人一看就觉得是贪心,按单位价值从高到低装就行,但这其实就是背包问题,贪心恰恰不保证最优解。
这类题给我们的启示是:选错算法模型比不会做更可怕。因为选错之后你会沿着错误的方向思考很久,浪费时间不说,最后交上去的代码还是错的。我的经验是,只要题目里出现“最大价值”“最小成本”“最优方案”这类词,第一反应不是去套贪心,而是先问自己三个问题:
- 局部最优能不能推导出全局最优?
- 有没有反例能推翻我的贪心策略?
- 这道题是不是应该用DP?
尤其在考试环境下,贪心算法的“证明”环节经常被忽略。大家总觉得“看起来对就行了”,但很多贪心策略的漏洞,恰恰藏在看似理所当然的细节里。如果你能快速举出一个反例,立刻转DP,往往是最优解。
2.2 动态规划:从记忆化搜索到状态压缩
动态规划是这套题的绝对主力。2018年的题里,至少有三四道是DP的变体,包括经典的背包问题、区间DP、状态压缩DP。
我当时刷题最大的体会是:DP的难点不在写转移方程,而在定义状态。状态定义一旦对了,转移方程就是水到渠成的事;状态定义错了,后面全乱。
以“多多君分糖果”这类题为例(具体题目是给不同权重的孩子分糖果,要求满足一定条件然后求最少糖果数),如果你定义的状态是“当前分到第i个孩子,当前剩余糖果数j”,那这个二维DP是能做的。但如果你把状态定义成“前i个孩子已经满足条件的最小糖果数”,就漏掉了“剩余糖果数”这个关键维度,错误地简化了问题。
这套题还特别喜欢考“区间DP”。区间DP的特征是:你优化的目标是一个区间上的某种最优值,而且大区间的解依赖于小区间的解。常见套路是先枚举区间长度,再枚举区间起点,然后枚举分割点。我当时整理过一个模板,到现在还在用:
for (int len = 2; len <= n; len++) { for (int i = 1; i + len - 1 <= n; i++) { int j = i + len - 1; dp[i][j] = INF; for (int k = i; k < j; k++) { dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + cost(i, j)); } } }这类题的坑在于初始化。很多同学忘记把长度为1的区间初始化好,或者忘记把不可达状态设成INF,导致答案永远是0。这些小细节,笔试的时候特别容易翻车。
2.3 图的遍历与最短路径:场景包装的重灾区
拼多多2018校招题里,有一类题是“物流配送”“好友推荐”“拼团关系链”——这些都是图的典型场景。对算法基础薄弱的同学来说,最大的障碍不是不会写BFS或Dijkstra,而是看不出这是一道图论题。
给你一个场景:“多多个用户之间有关注关系,如果A关注B,B关注C,那么C会出现在A的推荐列表里,现在给定关注关系,求某用户的二度人脉列表”。这就是典型的BFS层次遍历,只是没有直接给你邻接矩阵或邻接表而已。
我当时总结的经验是:题目里出现“关系”“网络”“路径”“可达”“最短”这些关键词,就要往图的方向去想。实现的时候注意三点:一是用邻接表而不是邻接矩阵,省空间也省时间;二是BFS要用队列,DFS要用栈或递归,不要搞混;三是visited数组的标记时机很关键——入队时标记和出队时标记,会导致完全不同的结果。
2.4 字符串与数学题:细节是魔鬼
这套题里有一批“不那么算法”的题,比如大数相加、字符串循环移位、括号匹配、回文判断等。这类题看起来简单,但想拿全分不容易。
举个大数相加的例子。题目会给你两个特别长的数字字符串,让你求它们的和。思路很简单:从低位到高位逐位相加,用一个变量记录进位。但我那次笔试,这道题挂了很多人,原因五花八门:
- 没有处理长度不同的情况,短的字符串越界了。
- 没有处理最后一位的进位,比如99+1得到00而不是100。
- 没有处理结果前导零的问题。
这些问题,每一个单独看都特别蠢,但在考场那种紧张状态下,就是会犯。我后来养成了一个习惯:写完代码先跑三个用例——最小输入、最大输入、边界输入。最小输入能暴露越界,最大输入能暴露超时和溢出,边界输入能暴露进位和特殊逻辑问题。90%的代码Bug都能靠这三类用例查出来。
3. 典型真题实战解析
3.1 真题一:多多的排列计算
题目描述大致是:给定一个由数字1到n组成的排列,按照字典序从小到大排列,求第k个排列是什么。看过LeetCode的同学应该知道,这就是“第K个排列”。当年这道题出现在拼多多的卷子里,迷惑性极强——它看起来像是让你把所有排列生成出来然后排序,实际上n可能非常大,全排列的复杂度根本过不了。
正确做法是使用“阶乘数系统”的数学方法。思路是这样的:最高位每固定一个数,剩下的排列数就是 (n-1)! 个。所以我们可以通过 k 除以 (n-1)! 来确定第一位数字,然后更新 k 为 k % (n-1)!,继续确定下一位。
我当时写这道题的时候,花了很多时间在“第k个”是从0开始还是从1开始的问题上。如果用0-based索引,k要减1;如果用1-based,直接用。我当时选择了一个最稳妥的方案:先把k做减一处理(k--),然后用0-based索引计算每一位。这样处理起来逻辑最清晰,也不容易出边界问题。
这道题的核心考点其实有两个:一是阶乘运算会不会溢出,n大于20的时候long long都不够用,所以必须用数组或字符串存储结果;二是二分的思想——每次用除法定位区间,用取余更新目标位置。这也是“按值定位”思想的经典应用。
3.2 真题二:多多的字符路径
这道题的原型是给定一个二维字符矩阵,从某个起点出发,每次只能走上/下/左/右四个方向,不能走重复格子,按顺序收集字符拼成一个字符串,求字典序最大的结果。剥掉外壳,它是DFS+回溯的典型题目,而且涉及一个很重要的剪枝优化:如果当前路径的字典序已经不可能超过已知最优解,就直接放弃。
说实话,这道题当年得分率很低,因为它有两个关键难点。第一个难点是DFS的终止条件不好定——是要走到没有可行的相邻字符为止,还是走固定步数?第二个难点是“字典序最大”的全局性——你不能只贪心地每一步选最大的那个字符,因为可能当前这步选了稍小的字符,下一步能接到一个极大的字符,整体字典序反而更大。
我和同学讨论之后,一致认为这道题最稳妥的思路是:先用DFS枚举所有可达路径,然后用一个全局变量记录最优答案。如果n和m都很小(比如不超过5),这种暴力枚举完全可行;如果矩阵很大,就需要加入剪枝,比如记录“当前路径字典序+剩余最大可能字符”有没有可能超过已知最优解。
这类题给我最大的教训是:不要一上来就写DFS,先估算状态空间。如果状态空间在可接受范围内,DFS暴力枚举反而是最不容易出错的方案。反过来,如果状态空间很大又没法剪枝,那大概率是你理解错了题意。
3.3 真题三:多多的求和问题
这是一道典型的“数论+二分”题目,原题大意是:给定一个数n,求和为n的连续正整数序列的所有可能方案。比如n=9时,9=4+5,也等于2+3+4,所以答案是2。
这道题其实有两种主流解法。第一种是数学公式法:连续序列的长度为len,起点为start,那么 [(start + (start+len-1)) * len] / 2 = n。这个公式可以化简为 (2*start + len - 1) * len = 2n。于是问题转化为:找一个len,使得 2n 能被 len 整除,且解出来的 start 是正整数。如果一个一个遍历len,时间复杂度是O(sqrt(n)),完全可行。
第二种是双指针滑动窗口法:维护窗口[l, r]的和,如果和小于n就右移r,如果和大于n就左移l,等于n时记录答案。这种方法的时间复杂度是O(n),思路简单不容易出错。
我当时面试的时候用了滑动窗口,因为公式法的整除条件很容易漏解,尤其是当len是偶数的时候,必须满足 (2n/len - len + 1) 是偶数,这个条件特别容易搞混。滑动窗口虽然慢一点,但胜在直观可靠。笔试里稳定拿分比追求最优时间复杂度更重要。
4. 常见问题与答题技巧实录
4.1 时间不够用怎么办
拼多多这套题总共的考试时间大概是90分钟到120分钟,有四五道编程题。我当年最大的感受就是:时间根本不够用。很多人挂在第一题上,非要写出最优解,结果后面的题全空了。
我的策略是:先把所有题都快速看一遍,每道题先写好暴力解或部分分的解,确保每个用例都能过一部分。然后重新审视哪道题最有可能在剩余时间内优化出Full Score,集中精力攻那一道。这套题是按用例给分的,暴力解通常能拿40%到60%的分,比空着强一百倍。
注意,考试系统一般有“编译并测试”和“提交”两个按钮,测试不扣分,提交才计入成绩。所以写完后一定要先测试再提交。别怕测试次数多,就怕不测试直接交。
4.2 输入输出格式的坑
笔试题目看起来在考算法,其实也在考你的输入输出处理能力。拼多多这套题里,有几个特别容易踩的输入坑:
- 第一行给一个整数T,表示有T组测试数据。很多同学只处理了一组。
- 数组可能用逗号分隔,而不是空格。你习惯性地用空格split,直接就解析错了。
- 输入数据可能有多余的空格和换行,不要用读一行然后split的方式,要用统一的tokenizer处理。
我后来养成一个习惯:每次笔试前,先把IO模板准备好。无论是“第一行是N,第二行是N个数字”还是“多组输入直到EOF”,都直接复制模板,不现场写。这个习惯帮我省下了大量时间。
4.3 代码的正确性验证方法
就算你觉得代码逻辑对,也要学会自己构造测试用例去验证。我最常用的是三类用例:
- 最小用例:比如n=1、数组长度为1,能最快暴露越界和逻辑漏洞。
- 最大用例:比如n=10^9,看会不会超时、会不会溢出。
- 反例构造:针对贪心或DP的策略,专门构造一个极端场景,验证你的算法会不会算错。
有一个经验是,所有“看上去很简单的题”,都要特别小心。笔试题目里那些读题只需要30秒的题,往往藏着最深的坑。这种题不要求你算法多高深,但你一旦大意,就是整道题零分。
4.4 笔试的答题顺序怎么安排
说一下我总结的答题顺序,不一定适合所有人,但值得参考。我的顺序是:
- 先把所有题读一遍,大概估算每道题的难度和所需时间,在草稿纸上标好“先做”和“后做”。
- 先做简单的字符串和数组题,先把该拿的分都拿到,稳定军心。
- 再做数据结构题,比如二叉树、链表相关。
- 最后再做DP、贪心这类需要长时间思考和验证的题。
这样安排的核心逻辑是:把“确定性高”的任务放在前面,把“不确定性高”的任务放后面。因为考试越到后面心态越容易崩,把难题放最后,即使没做出来,前面的分数也够了。
5. 复盘:这套题对现在的求职还有什么用
5.1 为什么现在仍然值得刷
其实距离2018年已经过去了很久,你可能觉得刷一套老题没什么意义。但我的看法刚好相反:校招笔试这块,技术栈和语言迭代很快,但算法题的核心考点几乎没有变过。拼多多2018年出的这些题,现在来看仍然是电商标配的题型模板——字符串处理、DP、贪心、图论、数学公式,这些东西在任何一届校招笔试里都是重头戏。
更重要的是,这套题很好地训练了“长题干阅读能力”。现在的笔试题目,题干越来越长,场景包装越来越花哨。如果你能静下心把拼多多这些题啃下来,再去做其他公司的题,你会发现自己的信息提取速度快了一大截。
5.2 从题目反推团队技术偏好
从这套题里,你还能看出一点有意思的东西:拼多多的技术面试官很看重“业务落地能力”。那些和拼团、物流、优惠券相关的题目,本质上就是在暗示“我们公司就是做这个的,我们希望招进来的人能快速把技术应用到真实业务上”。如果你在笔试之后的面试环节里,能主动把某道题和拼多多的实际业务场景做一个结合,会是一个很加分的表现。
我当时在面试中被问到“你做过最难的项目是什么”,我特意提到了自己用DP优化了一个配送路径规划的小项目,面试官明显来了兴趣,追问了很多细节。虽然不是直接对应笔试题目,但这种“把算法和业务结合”的能力,确实是拼多多这类公司很看重的。
5.3 延伸学习的建议
如果你刷完这套题之后觉得不过瘾,可以从下面几个方向继续深入:
- 把题里出现的DP模型全部总结一遍,包括背包、区间DP、状态压缩数字DP,每类找两三道同类题巩固。
- 把图的BFS/DFS应用场景熟悉一遍,尤其是拓扑排序和最短路径,这些都是电商场景的高频考题。
- 把数论里常见的整除、取余、质因数分解等知识点过一遍,因为很多看似“数学题”的编程题,本质是在考这些基本功。
我在刷完这套题后,最大的收获不是背住了某道题的解法,而是建立了一个“业务场景→算法模型”的反射弧。看到“拼单”想到“分组”,看到“优惠”想到“DP”,看到“网络”想到“图”。这种反射弧需要大量刷题才能形成,而拼多多的这套题,恰好是一个很合适的训练场。
5.4 最后一件事:别只刷题,要写博客复盘
我个人经验里最有效的刷题方式,不是闷着头一遍遍做题,而是每做完一道有价值的题,就写一篇博客记录下来。写的时候你会自然地把题目的场景、解法思路、复杂度分析、易错点都过一遍,这个过程比单纯做题的收获要大得多。很多知识你以为自己懂了,但一写出来就发现逻辑顺序是乱的。写博客、做输出,其实是在逼自己把“模糊的懂”变成“清晰的懂”。
我当年刷拼多多这套题的时候,博客里记了好几篇总结,后来面试前翻一翻,很快就能把高频考点和代码模板捡起来。这份东西到现在还留在我的笔记里,偶尔温习,依然觉得很受用。