
2019年那场PayPal实习生招聘的编程笔试我在倒计时还剩38分钟时刚把第三题跑通第四题连题意都没完全确认。这个场景我记到现在不是因为我最后通过了而是因为那道卷子的结构、它考察的东西和我后来参加的其他所有笔试都不一样。如果你正在准备外企的暑期实习或者单纯想看看支付公司会怎么考编程这篇内容应该能帮你省下不少走弯路的时间。我会把PayPal这套编程卷的题型布局、四道复现题目的完整推演、语言选型的隐藏分以及临场救火策略都拆开讲一遍。当时同批参加考试的人里流传一句话PayPal的笔试不像国内大厂那种八股算法全家桶它更像一份带着业务味的算法题读题的时间成本比想象中高。这句话我事后越想越认同。支付公司考编程考的从来不只是你会不会写快排和DP而是你在一个真实的业务约束下能不能干净地把问题拆掉。1. 先搞懂PayPal在筛什么人编程卷的出题逻辑与题量布局一打开笔试链接就是90分钟倒计时四道算法题难度从签到到压轴依次抬升。很多人以为这是标准的大厂算法套路其实我更愿意把它理解成一次接到需求→拆解问题→实现→验证的完整工作流模拟。PayPal的业务场景里大量逻辑不是难在算法本身而是难在边界条件、异常分支和代码的健壮性所以他们的笔试题也天然带着这种基因。1.1 为什么是90分钟四道题先说题量。90分钟四道题平均每道题22.5分钟。这个时间预算很微妙它刚好够一个熟练的人写一道Medium级别的题并跑通边界但如果卡在某道题超过半小时整场基本就乱了。PayPal的招聘团队显然不是随机拍的这个时间。四道题的设计遵循了一个经典的难度梯度第一题是让你热身的签到题第二题是数据结构应用题第三题开始需要一点思维拐弯第四题直接上一道需要完整算法设计的压轴。这种梯度在国内大厂笔试里也常见但PayPal的差异在于——它会用真实的支付业务场景把算法包起来比如交易单据的对账归并服务依赖的循环检测账单金额的等分合并。你如果习惯做LeetCode那种抽象题目读题阶段就可能浪费不少时间。另一个被很多人忽略的点是这场笔试并不追求你AKAll Killed全部通过。PayPal实习生的HC数量有限笔试的功能更接近快速排除一批不合适的人而不是选出所有能解出四道题的人。所以它的判分逻辑里时间分和代码质量占比很高纯粹的AC主义在这里反而容易吃亏。1.2 分数结构里不会告诉你的隐藏信息我记得当时成绩单只会显示一个总分但后来通过内部渠道了解判卷过程远比一个总分复杂。第一部分AC是给部分分的。你如果第四题只写出了暴力解法只要通过了几个小数据测试点就能拿到对应的分数。这跟国内一些笔试非AC即0分的机制不同它更看重你在有限时间内的产出能力。第二提交次数和时间是隐性的扣分项。同样一道题一次AC和提交了八次才通过在自动化评分系统里呈现出的代码稳定度是完全不同的。许多在线笔试系统会记录每次提交的快照面试官review代码时如果看到一连串的编译错误和超时提交印象分会打折扣。第三边界用例的覆盖度是最关键的得分点。PayPal的题面里经常出现数组可能为空金额可能为负数输入可能包含超大数这类容易被忽略的约束。能把这些边界处理得明明白白的人在支付场景里就是比只会在LeetCode上AC的人更值钱。这也解释了为什么很多人在网上吐槽PayPal笔试明明全AC了还是挂了——因为你的代码可能在边界用例上翻车了或者在代码风格上让阅卷人皱眉。关于阅卷人到底怎么看代码我在第4章会专门展开。2. 题型起手式这几类问题占了笔试80%的分数复盘那套卷子和我后来收集到的同批次题目可以清晰看到PayPal编程卷的考点分布。它不是漫无边际的算法地图而是高度集中在六个方向。如果你想把备考效率拉满优先掌握这六类的判断标志和解法骨架比盲目刷300道题管用得多。2.1 字符串与模拟题业务逻辑的包装外壳这类题几乎必考通常作为第一题或第二题出现。典型特征是给你的输入是字符串、列表、文件路径要求你按规则做转换、过滤、计数。PayPal特别喜欢把支付票据、邮件地址、用户ID这些业务元素塞进题面。我的建议是看到字符串题先不要急着写循环先想清楚三件事数据范围决定能不能暴力、规则里的否则除了分支是否都覆盖、输出格式是否要求严格一致。字符串题的翻车往往不是算法难而是漏掉了某个规则分支。比如判断两个表达式是否等价的题核心就是要用哈希表把变量系数归拢再比较展开后的结果而不是真的去枚举字母赋值。2.2 哈希表与排序的结合第二类高频题型是哈希表排序的组合。比如给两个用户的消息ID列表找出共同消息并按字典序去重输出或者给一批交易记录按金额出现的频率排序。这种题本身不难但它考察的是你对容器操作的熟练度以及能否在AC之外保持代码简洁。我在实际考试中遇到的情况是哈希表的思路秒出但排序规则里藏着坑——比如要求频率相同时按ID从小到大排如果你用默认排序或者排序函数里漏了这个次级关键词答案就会错。这类细节最容易被忽略也是最值得在自测用例里覆盖的。2.3 贪心与区间问题支付系统里有大量资源调度、任务合并的场景所以贪心类的区间调度题也是常客。典型题目包括会议室预订冲突检测、多笔交易的时间区间合并、任务调度最短时间。解这类题的关键是先排序再贪心。排序的依据可能是结束时间、开始时间或者区间长度一旦选错方向整个贪心策略就崩了。我的经验是只要题面出现最多最少能否覆盖这类词第一步就先把区间按右端点排序列出来观察相邻区间的关系往往思路就通了。2.4 二分答案与边界收敛有一类题不会直接告诉你用二分而是要求你找到满足条件的最小值/最大值。比如在保证不超过预算的前提下计算出最大可分配的单笔金额。这种最值问题如果能转成给定一个值判断是否可行的判定问题就可以用二分答案。二分本身不难难的是收敛边界。很多人在while循环的left、right更新上患得患失导致死循环或漏解。我的建议是统一用while (left right)加mid (left right) 1的模板并且把判断条件写成一个独立的check函数这样逻辑清晰也好调试。2.5 图论浅层应用拓扑排序与连通性PayPal这种微服务架构遍布的公司服务依赖关系是天然的图论考题素材。我参加的那场笔试的压轴题就是给定一堆服务的依赖关系判断是否存在循环依赖并输出一个可启动顺序。说白了就是拓扑排序但题面被包装成了部署任务调度。拓扑排序的BFS模板很简单但要小心两个细节一是输入可能给出重复依赖二是图可能不连通存在多个入度为0的起点。前者要用set或去重逻辑处理后者决定你最后的输出顺序是否符合题目预期的字典序。另外并查集也要顺手准备判断两个节点是否连通、合并集合这类操作在支付风控场景里也是高频考点。2.6 动态规划入门级模型是底线PayPal的笔试不会出太变态的DP题但常见的背包模型、最长递增子序列、爬楼梯变体是底线。压轴题如果不用图论大概率会用DP来卡时间。备考时不需要去死磕插头DP、树形DP这种高难度玩意儿把经典模型的状态设计逻辑吃透就够用。以我的观察这类题的难点在题面伪装——比如把背包容量包装成风控预算把物品重量包装成每笔交易的金额。你只要能剥开包装认出模型剩下的就是套模板。3. 四道复现题目的完整推演从读题卡壳到跑通边界以下题目是我根据当时的笔试回忆结合同批同学的反馈做了脱敏重写核心考点和卡点保留原汁原味但细节上有出入如果有当年一起考过的朋友看到了应该会会心一笑。这套题目的整体排布是一道字符串栈模拟、一道哈希加排序、一道DFS回溯剪枝、一道拓扑排序。下面每一道我都按题目描述、我的卡点、正确思路、核心实现、复杂度五个维度来复盘。3.1 第一题等价表达式判断题目描述给定两个字符串表达式只包含小写字母、加号、减号和左右括号例如a-(bc)和a-b-c。每个字母视为一个独立的变量判断两个表达式是否恒等。我的卡点这道题其实不算难但我一开始走了弯路——我想把字母代入具体值去验证比如a1, b2, c3但这样只能验证单点无法证明恒等。还好我很快意识到正确的做法是展开表达式把每个变量的系数算出来然后比较变量到系数的映射是否完全相同。正确思路用两个栈或一个预处理符号栈来处理括号展开。维护一个全局的sign表示当前项的正负号遇到或-时更新当前项的符号遇到括号时把括号前的符号压栈括号内遇到符号时需要结合栈顶的符号再做一次翻转。最后把所有变量项的系数累加到哈希表里。两个表达式如果哈希表完全一致就返回等价。核心实现的片段大致是这样#include bits/stdc.h using namespace std; mapstring, long long parse(const string s) { mapstring, long long coeff; stackint st; st.push(1); int sign 1, i 0; while (i s.size()) { if (s[i] ) { i; continue; } if (s[i] ) { sign st.top(); i; } else if (s[i] -) { sign -st.top(); i; } else if (s[i] () { if (i 0 s[i-1] -) st.push(-st.top()); else st.push(st.top()); i; } else if (s[i] )) { st.pop(); i; } else { string var; while (i s.size() isalpha(s[i])) { var s[i]; i; } coeff[var] sign; } } return coeff; }说明一下上面的代码简化了连续字母作为变量名的语义真实考试里每个字母都视为独立变量时解析逻辑会更简单直接取单个字母即可。重点在于符号栈的管理这是这道题唯一的坑。复杂度每个字符只遍历常数次时间O(n)空间O(n)。3.2 第二题共同收件人过滤题目描述两个邮件服务节点分别维护了一份收件人ID列表每一行是一个非负整数ID。请找出两个列表中都出现过的ID去重后按升序输出。如果结果为空输出空行。我的卡点这道题没有太多卡点思路秒出。但我在一开始排序时写反了——题目要求升序我写成了默认的降序好在自测时发现并修正了。另一个容易踩的坑是输出格式每行一个ID如果末尾多了空格或者最后多了一个换行在严格判题的OJ上会报Presentation Error。正确思路用一个哈希集合存第一个列表再遍历第二个列表把命中第一个集合的元素放入另一个集合做去重最后对这个集合排序输出。PayPal这种题喜欢包一层业务外衣但核心就是集合运算。复杂度时间O(n m klogk)空间O(n)。3.3 第三题账单等额分配题目描述给定一组整数表示的账单金额和一个正整数K判断能否把这些金额分成K组使得每组金额总和相等。每个账单只能使用一次。例如[3, 3, 3, 3]和K4可以分成四组每组和为3但[4, 3, 2, 3, 5, 2, 1]和K4每组和应为5是可以分的。我的卡点这道题我第一反应是DP但仔细一看数据范围金额数量可能是15个左右这个规模用状态压缩DP又有点浪费而且我也没有十足的把握在笔试时间内写对状压。实际上PayPal这类外企的笔试时间紧张DFS加剪枝往往是性价比最高的解法。正确思路先判断总和是否能被K整除然后排序从大到小降低搜索分支数量用DFS把每个数字逐个分配到K个桶中。剪枝的关键有三个当前数字放不进任何桶就回溯如果当前桶的和为0且放入失败说明后面的桶也会失败相同数值的连续元素避免重复尝试。这道题不需要贴完整代码核心的DFS框架背熟就行bool dfs(vectorint nums, int k, vectorlong long bucket, int idx, long long target) { if (idx nums.size()) return true; for (int i 0; i k; i) { if (bucket[i] nums[idx] target) continue; if (i 0 bucket[i] bucket[i-1]) continue; bucket[i] nums[idx]; if (dfs(nums, k, bucket, idx 1, target)) return true; bucket[i] - nums[idx]; if (bucket[i] 0) return false; } return false; }复杂度指数级但剪枝后在小数据量下非常快这恰恰是笔试环境更看重的够用且好写。3.4 第四题服务启动顺序与循环依赖题目描述一套微服务系统有N个服务编号从0到N-1给定M个依赖关系每个关系表示为a b表示服务a依赖服务b即b必须先于a启动。请输出一个合法的启动顺序如果存在循环依赖导致无法启动输出Cycle。我的卡点第四题我连题意都差点没读完因为到这个时候时间已经不多了。但幸运的是我一眼认出这是拓扑排序的裸题赶紧先写了BFS框架把入度为0的节点入队按顺序弹出并更新邻接节点的入度。最后判断弹出的节点数是否等于N不等于就说明有环。正确思路建立邻接表和入度数组。题目没有要求字典序所以直接用队列就行。如果要求字典序把普通队列换成优先队列即可。输出顺序就是出队顺序。核心代码片段vectorint topo(int N, vectorpairint,int deps) { vectorvectorint adj(N); vectorint indeg(N, 0); for (auto [a, b] : deps) { adj[b].push_back(a); indeg[a]; } queueint q; for (int i 0; i N; i) if (indeg[i] 0) q.push(i); vectorint res; while (!q.empty()) { int u q.front(); q.pop(); res.push_back(u); for (int v : adj[u]) { if (--indeg[v] 0) q.push(v); } } if ((int)res.size() ! N) { cout Cycle endl; return {}; } return res; }复杂度O(N M)。这里我复盘完最大的感受是四道题没有一道需要用到特别冷门的算法全是基础中的基础但每一道都在考察你在有限时间内不犯低级错误的能力。字符串题考符号栈集合题考哈希排序DFS题考剪枝图论题考模板熟练度。这些东西在LeetCode上都是高频题只在于你练得够不够狠。4. 笔试语言选型与阅卷潜规则AC之外的分差来源很多人笔试前都会纠结一个问题用C、Java还是Python我的结论是如果你不是某种语言的绝对大神选你最熟、最不容易写出语法错误的语言。但如果实力相当PayPal这种偏工程风格的笔试C和Java会比Python更讨喜一些原因不只是性能而是它们天然要求你关注类型和内存这和支付系统的工程气质更匹配。4.1 三门主流语言的笔试对比语言写码速度标准库丰富度调试难度阅卷人眼中的工程感C中高STL中高强但容易在内存细节上翻车Java中高Collections中强代码结构清晰Python快极高低稍弱但可读性好我当年用的C原因很简单,刷题时主要语言就是它。但事后反思如果我对Python更熟第三题的DFS剪枝写起来会更快因为Python的切片和列表操作能让代码短很多。笔试的核心是在限定时间内产出可运行、覆盖充分的代码所以语言选型的唯一标准还是熟悉度。4.2 阅卷人想从代码里看到什么通过一些朋友后来给的反馈PayPal的笔试代码是会有工程师人工review的而且占分不低。人工review最关注的几个点按权重排列大约是正确性是否覆盖了所有分支、命名与结构、边界处理、注释与思路表达。我见过有人在笔试里写几百行在一个函数里的面条式代码把所有逻辑堆在一起AC了但review印象很差。也见过有人变量名是a1、a2、temp看得人头皮发麻。正确的做法是把读入、核心逻辑、输出分成三个块函数名用parse、canDivide、topoSort这种能望文生义的命名。哪怕时间再紧至少保证主流程清晰。4.3 代码之外的自测矩阵笔试最容易翻车的往往不是思路而是边界。我后来总结了一套自测矩阵每次写完必跑一遍这套东西帮我避开了无数个隐藏的Runtime Error。空输入数组为空、字符串为空、K为0时程序是否崩溃单元素输入只有一个节点、一个账单时逻辑是否依然正确全相同元素所有值相等时排序、去重、计数逻辑是否正常最大规模输入数据量达到题目上限时是否会超时或溢出负数与零金额可能出现负数吗ID可以是0吗这些在题面里往往有隐藏约束一定要读清楚。我在第二题的排序上栽过跟头就是因为没有用包含重复元素的用例去测。你可以把这些用例提前写成一个简单的测试脚本每次提交前跑一遍两分钟时间能救回十分以上的分数。5. 临场时间管理与救火策略先拿分还是先攻难题很多人在笔试里最大的问题不是不会做而是时间分配一塌糊涂。比如第一题签到题做了30分钟因为一直在打磨输出格式或者第四题压轴题死磕40分钟无果导致第三题没时间写。这些都是我在真实考场上看到过的悲剧。5.1 前10分钟的通读与分级拿到题先别急着动键盘。用5到10分钟把四道题全部读一遍每道题在草稿纸上记三行题型关键词、数据范围、可能的坑。然后给题目标个等级A级是秒懂思路且数据范围友好B级是有思路但需要仔细处理边界C级是暂时没思路或者数据范围很大需要纸面推演。我当时的排序是第二题和第一题是A级第三题B级第四题是C级。这个排序直接决定了我后续的时间投入比例。第一题做20分钟第二题15分钟第三题预留35分钟第四题如果还有剩余时间就写暴力。5.2 卡题25分钟定律及时止损与暴力兜底我给自己定了一条铁律一道题如果连续25分钟没有实质性进展立刻停下来。这里实质性进展不是指在想而是指你已经写出了可以运行的核心代码框架或者已经在纸上画出了完整的解法流程。如果25分钟过去连代码都没开始写说明思路可能走偏了继续死磕只会拖垮后面的题。但停下来不等于放弃。如果第三题一时半会儿找不到最优解我会立刻切换成暴力解法先把小数据范围的分拿住。PayPal的给分机制里部分AC是算分的暴力解的收益往往比你想的高得多。我身边有位同学就是第四题只写了暴力把省下来的时间全部用于补第二题和第三题的边界用例最后成绩反而比硬刚压轴题的人好。5.3 最后5分钟的保命提交离考试结束还剩5分钟时不要再写新功能了做三件事第一把你已经通过测试的代码重新提交一遍保证至少有一个稳定得分。第二检查所有输出格式是否有多余空格或换行。第三把那些可能越界的变量类型从int改为long long尤其是涉及金额、人数、总和的题目。这个阶段最重要的是止损。很多人在最后几分钟想给第四题补一个特判结果破坏了原本能跑通的代码导致前功尽弃。稳住别浪保住已有的AC比不切实际的AK重要一百倍。6. 笔试只是起点从编程卷到面试的综合能力衔接笔试通过后你的表现会随着这份代码一起被带到后续面试。很多人以为面试官只看简历其实不然。如果面试官手里拿着一份你笔试时的代码他真的会问你第三题的DFS剪枝能不能解释一下为什么这个剪枝是安全的这种问题如果你的代码能自洽解释会非常加分如果连自己都忘了当时怎么写的就尴尬了。6.1 笔试笔记留痕面试时拿出来讲我的习惯是笔试过程中每道题做完以后在草稿纸或编辑器里留几句注释写下核心思路和复杂度。时间允许的话我会在最后把每道题的解法用一两句话总结。面试时如果被问到我能直接说第三题我用的DFS加剪枝核心是排序后从大到小遍历遇到桶和为0时提前回溯因为后面的桶和必然也等于0这一步减少了重复搜索。这种表达比支支吾吾地回忆要专业得多也能体现你的工程复盘能力。6.2 支付类岗位面试的高频延伸异步编程与并发安全笔试只是第一关PayPal的后续面试——尤其是技术面——会更深入地考察你在真实系统里的动手能力。一个很典型的延伸方向是并发和异步支付系统里大量操作是异步的比如回调通知、对账任务、跨服务调用。面试官很有可能会顺着笔试里的任务依赖话题问你如果这些服务是异步调用的你怎么保证最终一致性。这类问题不要求你当场写出完整框架但你需要知道CompletableFuture、线程池、消息队列这些基础组件是干什么用的。我的建议是笔试通过后到面试前的空窗期优先补齐三块知识异步编程模型、并发安全的基本概念synchronized、ConcurrentHashMap、原子类、以及分布式系统的最终一致性思路。这些内容不一定会被直接问但能让你在聊项目时更有底气。6.3 时间规划与刷题清单如果你现在还在准备阶段我给你一个可执行的备考时间线第一阶段2周刷LeetCode的Top 100高频题重点覆盖数组、哈希表、双指针、字符串、排序、二分、DFS、BFS、拓扑排序、基础DP。第二阶段1周针对性刷题围绕我上面提到的六大题型每类刷10道左右。注意不要只刷题要总结每类的判断标志和解法骨架。第三阶段3天模考训练。用在线OJ自己掐时间做一套模拟卷四道题90分钟完全按真实考场节奏来。模考的目的不是刷题量而是训练时间分配和心态。刷题量不是最重要的重要的是你能不能在一道新题面前用3分钟识别题型用5分钟构建思路用剩下的时间写出干净的代码。这种能力才是PayPal笔试真正考察的东西。最后再分享一个小技巧准备一个本地测试脚本专门用来跑边界用例。脚本不用多复杂维护一个测试用例列表每次写完代码一键跑完所有用例包括空输入、最大输入、重复元素、负数等。我的真实感受是高分的人往往不是思路最惊艳的而是那些在细节上最稳的人。笔试不只是算法比赛它是一次对你能否在真实业务压力下交出高质量代码的压力测试。