
快手2020校园招聘秋招笔试--算法B试卷深入拆解与实战复盘先说结论算法笔试是校招筛人最狠的一关没有之一。快手2020校园招聘秋招笔试的算法B卷虽然不是最顶尖的难度但它非常典型地代表了国内一二线大厂对算法工程师候选人的核心要求——不考偏题怪题全靠基础功和临场思维。当时我身边不少同学因为这套卷子拿到了面试机会也有不少人栽在了一些非常基础的细节上。这篇文章索性把这个卷子彻底拆开结合我自己的刷题经验、复盘记录以及招聘反馈从出题思路、核心考点、实操流程到高频坑位全部铺开讲一遍希望对正在准备算法岗笔试的同学有实实在在的帮助。这个B卷需要你具备什么能力简单说就是三块一是扎实的数据结构和算法基础二是快速建模和推导的能力三是在有限时间内写出无Bug代码的工程素养。它适合谁大三/研二准备秋招或暑期实习的同学或者想系统评估自己算法水平的在职工程师都可以拿它当试金石。1. 试卷整体设计与考核点拆解1.1 B卷的定位与难度坐标快手2020秋招算法类岗位分了多套试卷B卷属于偏算法基础、工程实现导向的中等难度卷整体风格和字节跳动、腾讯的笔试风格接近但比阿里一些数学推导偏多的卷子更偏代码实操。它的定位很明确筛掉那些简历写得天花乱坠、但连基本代码能力都不过关的候选人。整张试卷以编程题为主题量大概在4到6道时间在90到120分钟之间需要在线编译运行。常见的题型组合是两块1到2道纯数据结构题链表、二叉树、数组2道中等偏难的算法设计题动态规划或贪心为主偶尔穿插一道数学建模或字符串处理题。B卷的难度比A卷友好但比C卷更能考察代码能力属于你掌握了套路就很容易过但基础不牢就会很痛苦的中间档。这里要特别聊一下为什么快手笔试题喜欢这种中等偏易细节极多的搭配。大厂笔试的核心目的不是筛出天才而是筛掉不稳定因素。真正能在一小时内写完一道困难题的人本来就少笔试阶段如果全出难题区分度反而低。而把题目难度控制在中等却把边界条件、数据范围、输入输出格式这些细节埋得很深能让基础扎实的候选人稳定得分让临时抱佛脚的候选人暴露原形。1.2 输入数据范围与时间复杂度的隐含约定拿到考题先看数据范围这是笔试最重要的习惯没有之一。快手这套B卷在题干里通常会给明n的取值范围比如n 10^5或者n 10^3。不要小看这一行信息它决定了你的算法选型。如果n 10^3O(n²)大概率能过直接用暴力或者简单的动态规划。如果n 10^5O(n²)必挂必须想O(n log n)或者O(n)的解法。如果涉及字符串匹配且长度在10^5级别那基本就是在暗示你用KMP或者哈希而不是朴素匹配。我见过太多同学明明写出了正确算法却因为没用对复杂度等级导致超时全场心态炸裂。复杂度分析不是笔试之后复盘时才做的事而是看完题目三秒内就要做的判断。另外B卷里很多题目的输出要求非常具体比如如果不存在则输出-1结果对1000000007取模。取模题一旦出现说明结果很大必须用long long存储中间值否则在乘法过程中就会溢出。这类细节一旦写错样例都过不了。1.3 知识点覆盖大盘点从数据结构到经典算法结合我对多套快手试卷的横向对比B卷的知识点分布大致如下知识点类别出现概率典型形式数组/链表操作极高链表反转、合并有序数组、双指针扫描二叉树高层级遍历、最近公共祖先、路径和问题栈/队列高单调栈、单调队列、括号匹配类问题动态规划极高背包变体、最长递增子序列、二维DP贪心算法中等区间调度、跳跃游戏、分配问题字符串中高KMP next数组、字符串哈希、回文判断图论中等Dijkstra、拓扑排序、并查集数学/位运算较低快速幂、找规律、异或运算这里要重点提醒KMP几乎是B卷必考的隐藏知识点。哪怕题目表面上不是直接让你写KMP也会在字符串匹配、重复子串、循环节这类问题上用到它的思路。热搜词里那些在KMP算法中对于模式串pabacaba其next数组之类的问题就是这类知识点的直接体现。建议把KMP的next数组计算过程背得滚瓜烂熟这属于性价比极高的投入。2. 核心算法考点的准备策略与原理剖析2.1 排序与二分看似简单却处处是坑排序算法虽然是基础中的基础但在B卷里很少让你手写快排或者堆排而是会隐藏在求第K大找中位数合并区间这类题目里。我建议你重点掌握的是排序的稳定性应用和二分查找的边界写法。快速排序掌握partition过程的双指针写法能处理数组中有重复元素的情况。归并排序重点不在排序本身而在于它能顺带解决逆序对问题这个考点在笔试中经常出现。二分查找考查点不是你会不会写二分而是你能不能一次写对边界。我强烈建议你统一使用left right这种写法并且每次更新时left mid 1、right mid - 1不要混用否则死循环的Debug时间会占掉你宝贵的做题时间。我在刷题时养成了一个习惯把二分的所有变体——查找第一个大于等于target的位置、最后一个小于等于target的位置、旋转排序数组中的查找——全部整理成模板并记住每种模板的边界含义。到了笔试现场不需要重新推理直接套模板既快又稳。2.2 动态规划B卷的分水岭题型动态规划在B卷中的地位是压轴级的通常占据两道编程题且区分度最高。很多同学对DP的恐惧在于状态定义想不出来这里我分享一个比较实用的思考路径先判断这道题是否满足最优子结构和重叠子问题然后按照以下顺序尝试状态定义一维DPdp[i]表示以第i个元素结尾的最优值如最长递增子序列LIS或者前i个元素的最优值如打家劫舍问题。二维DPdp[i][j]表示前i个物品和容量为j时的最优值01背包经典状态或表示区间[i, j]上的最优值区间DP。状态压缩DP当状态量很小如n 20时可以用位运算表示集合的状态。B卷的DP题往往不是裸的模板题而是加了一层包装。比如背包问题不会直接说给你物品和容量而会包装成投资组合任务分配工作负载均衡等场景。这时候要做的不是着急写代码而是先把题干的变量映射到背包问题的三要素物品、重量、价值。另外我必须强调动态规划题千万不能用递归配上不带记忆化的朴素DFS去硬刚尤其是n大于1000的数据范围指数级递归会直接把系统栈打爆。如果要先写暴力验证思路也请用带备忘录的自顶向下写法也就是记忆化搜索至少能拿到部分分。2.3 贪心算法如何证明贪是对的贪心算法在B卷里的出现频率不低很多考生的问题不是不会写贪心而是不知道这道题该不该贪。这个问题的标准回答是如果你能找到一个单调的排序规则使得每一步的局部最优选择都不影响后续选择的可行性那大概率是贪心。举个例子经典的区间调度问题——给定若干区间选择最多互不重叠的区间。贪心策略是按区间终点排序然后依次选择终点最小且与已选区间不重叠的区间。这个策略为什么正确因为终点越早留给后续区间的空间就越大。但如果题目换成求覆盖整个线段的最少区间数贪心策略就变成按起点排序每次选择起点小于当前覆盖位置且终点最远的区间。所以贪心题要多积累模型。B卷常见的贪心模型有区间问题选择最多不重叠区间、最少区间覆盖、跳跃游戏计算最少跳跃次数、分糖果两头扫描、股票买卖计算最大利润。每类模型都有固定的贪心方向和证明套路刷题时不要只AC了事要顺手写下为什么贪心在这里是对的这样到了考场上才能快速识别题型。2.4 字符串算法KMP与哈希的实用价值字符串题在B卷中是不算难但容易下手慢的模块。如果你只会朴素匹配遇到10^5级别的字符串匹配题几乎必挂。这里有两个主流方案KMP算法预处理模式串的next数组匹配过程回退的时间复杂度是O(nm)。这是字符串匹配的金标准务必要能默写。滚动哈希Rabin-Karp用哈希值比较子串是否相等配合前缀哈希数组可以O(1)判断任意两个子串是否相同。在最长重复子串字符串轮换回文子串数量统计等题目里非常好用。以热搜词中的KMP题为例对于模式串pabacaba它的next数组计算过程是怎样的next[i]定义为模式串前缀p[0..i]的最长相等真前后缀长度有的版本定义为失配后跳转的下标注意统一标准。手算一遍就能发现这个串在b和c交界的地方存在前缀后缀匹配所以next值不是单调的这也是KMP题的经典陷阱——死记公式容易错必须理解匹配失败时利用已匹配部分的信息跳跃这个核心思想。另外B卷里偶尔也会出现一个不算超纲但容易忽略的考点字符串的字典序排序和自定义排序规则。这题涉及的是Java的Comparator或者C的sort函数自定义仿函数注意比较器必须满足严格弱序否则会报错或者结果混乱。3. 实操过程与核心环节实现3.1 拿到题目后的标准答题四步法很多同学笔试失败不是因为不会做而是因为流程混乱。我自己在多次笔试后总结了一个固定流程这里分享出来读题三遍提取变量。不急着写代码先用笔在草稿纸上把输入、输出、数据范围、特殊条件列出来。特别留意非负整数升序数组不包含重复元素这类限定词它们往往决定了某些解法是否可用。先想暴力解再优化。哪怕最终要写O(n log n)的解我也建议你花一分钟想一下暴力解O(n²)怎么写。这能帮你确保自己对题意的理解没有偏差也给后续优化提供了对照组。预估复杂度和数据规模是否匹配。如果n10^5而你的算法是O(n²)立即止损换思路。不要抱着我优化一下常数就能过的侥幸。写完代码后先用草稿纸上的小样例自测再构造2到3个边界用例测试。以一道典型的合并区间题为例输入若干区间要求合并所有重叠区间。先排序再扫描是最标准的解法但如果不注意细节容易在区间合并后可能继续和后面的区间重叠这个环节踩坑导致合并结果错误。这道题的核心代码如下def merge(intervals): if not intervals: return [] intervals.sort(keylambda x: x[0]) res [intervals[0]] for left, right in intervals[1:]: # 当前区间的起点小于等于合并区间的终点说明重叠 if left res[-1][1]: res[-1][1] max(res[-1][1], right) else: res.append([left, right]) return res这段代码的关键在更新res[-1][1]时使用max因为排序只保证了起点有序没保证终点有序。3.2 动态规划题的标准拆解案例B卷有一类最常见的DP题给定一个数组求满足某个条件的最优值。这里我用最长有效括号问题做一次完整拆解因为它既考察栈的应用也考察DP建模两者都能写。题目给定一个只包含(和)的字符串找出最长有效格式正确且连续括号子串的长度。暴力思路是枚举所有子串并用栈判断是否为有效括号复杂度O(n³)显然不行。用栈可以做到O(n)方法是遍历字符串遇到(将下标入栈遇到)时如果栈非空则弹栈计算当前下标与栈顶下标的差值更新最大值如果栈为空说明遇到多余的右括号将当前下标入栈作为新的哨兵。这个思路能AC但容易在栈里存什么上出错。DP写法是dp[i]表示以第i个字符结尾的最长有效括号长度。当s[i]是)且s[i-1](’时dp[i] dp[i-2] 2当s[i]是)且s[i-1])’时如果s[i-dp[i-1]-1](’则dp[i] dp[i-1] dp[i-dp[i-1]-2] 2。这里最关键的是第二层转移中的dp[i-dp[i-1]-2]很多人漏掉这个把更前面的有效长度接上的步骤导致结果偏小。其实这个步骤可以用一个简单的例子帮助理解()(())当处理到最后一个)时前面的有效长度是2而dp[i-dp[i-1]-2]相当于把最前面那组()也接进来。3.3 图论题中的Dijkstra与拓扑排序B卷偶尔会出现图论题它不像前端或客户端岗位的笔试题那样偏模拟而是更偏向最短路和拓扑排序的应用。Dijkstra是最短路中的高频考点特别是在堆优化的加持下复杂度为O((VE)log V)在稀疏图中非常高效。笔试时优先使用priority_queueC/heapqPython把(距离, 节点)作为元组入队并按距离从小到大弹出。另一个容易考的图论算法是拓扑排序通常和课程表类问题绑定出现。核心思路是统计每个节点的入度入度为0的节点先入队列弹出后更新邻接点的入度。如果最后弹出的节点数不等于总节点数说明存在环。这个算法本身很简单但B卷的考法往往会改包装成任务依赖关系包管理器依赖解析等场景。3.4 手写快排与堆排的现场避坑虽然笔试环境一般不要求你手写排序算法但B卷偶尔会有用堆实现TopK这类的题目。比如从N个数中找出最大的K个数很多同学第一反应是全排序再取前K个复杂度O(N log N)如果N在10^7级别就直接挂掉。正确做法是维护一个大小为K的小顶堆遍历数组时如果当前元素大于堆顶就替换堆顶并调整堆。这样做的时间复杂度是O(N log K)内存占用O(K)在K远小于N时性能差距巨大。这里有一个容易踩的坑Python的heapq默认是小顶堆找最大K个时直接使用没问题但如果你要维护的是大顶堆需要把元素取负再入堆。很多人在对比堆顶、弹出堆顶、更新堆顶时逻辑混乱导致结果差之千里。建议平时就把这个模板写到自己的代码库里笔试时直接默写。4. 常见问题与排查技巧实录4.1 边界条件笔试失分的最大杀手我总结了B卷考生在边界条件上最常见的几个翻车现场空数组/空字符串。大部分题目如果没有特殊说明输入都可能为空。如果答案为0或空列表需要先做判空不要直接索引导致运行时错误。数组长度为1的情况。很多循环类算法在长度为1时可以直接返回如果强行走循环反而会越界。整数溢出。C和Java的int是32位范围约±21亿题目如果给到10^9级别乘法就会溢出因此要立即切换为long long或long。减法结果为负、取模为负。在C中负数取模的结果是负数这会导致数组下标越界。正确的做法是先加模数再取模(x % MOD MOD) % MOD。笔试时一旦报出运行时错误第一件事不是读错误信息而是检查上面四条。我见过太多人花十分钟去查为什么逻辑没问题却报错结果发现是没用long long。4.2 输入输出的处理技巧别让IO拖后腿在线笔试通常要求从标准输入读取输出到标准输出但不同平台的数据读取方式有差别。快手用的是牛客网支持多组输入常见的坑是如果输入是多行整数每行数量不同需要用split并按需读取不要假设每行固定。如果题目要求输出浮点数并保留几位小数使用格式化输出而不是直接print。大数据量输入时Python的input()逐行读取够用但如果数据量极大超过10^6行推荐使用sys.stdin.buffer.read().split()一次性读取速度能快一个量级。我一般在考试前5分钟会先写好一个输入输出模板把sys.stdin.read解析和输出helper都准备好这样正式看题时就不用再花时间处理IO。4.3 超时与内存的限制在线判题系统的真实压力B卷的判题环境一般对单题时间限制是1到2秒内存限制256MB。如果代码写了很深层的递归比如在计算斐波那契时用不带记忆化的递归当n达到10^5时必然栈溢出。如果是并查集没有路径压缩在极端情况下也会超时。这里要单独说一下Python的递归默认递归深度是1000左右就算你用sys.setrecursionlimit(1000000)强行扩大Python的函数调用开销依然很大深度过深照样会出现段错误或超时。所以在Python中写图遍历时尽量用显式栈代替递归写DFS时用stack写BFS时用queue。4.4 笔试环境与编译器细节快手笔试使用牛客网的页面编辑器而不是本地IDE。这个编辑器非常基础没有自动补全没有断点调试只能在打印输出后观察。所以平时刷题时建议刻意练习一次性写出正确代码的能力不要依赖本地IDE的报错提示。笔试时还有一个小坑代码模板里通常有if __name__ __main__:这种结构有同学会把自定义函数写在模板后面导致运行报未定义错误。正确做法是所有函数定义写在main函数之前或者把所有逻辑都放在main里。5. 备考路线与现场策略5.1 考前三个月的刷题规划按阶段突破针对快手B卷的难度和风格我建议你把备考分为三个阶段第一阶段第1到4周基础夯实。主攻数组、链表、栈、队列、哈希表以及二分查找、双指针、滑动窗口。推荐按专题刷题每天2到3题重点练速度单题控制在30分钟以内。第二阶段第5到8周算法进阶。集中突破动态规划、贪心、DFS/BFS、回溯外加KMP和并查集。这一阶段的题目难度要大一些允许单题花40到60分钟但必须做到写完能解释清楚复杂度。第三阶段第9到12周模拟实战。用牛客网或LeetCode的模拟考试功能全真模拟快手笔试的时长和题量。重点是训练时间分配如果3道题里有两道容易一道难先保证容易题全过再用剩余时间冲难题。5.2 现场做题顺序先易后难稳住基本盘笔试现场最忌讳的就是在难题上死磕。我的策略是先把所有题目快速浏览一遍按难度分成秒杀题稳答题冲刺题三档。秒杀题5分钟内完成稳答题15到20分钟内完成冲刺题放到最后30分钟做。难点在于如何快速识别稳答题。我的标准是如果读完题目后30秒内能想到正确的数据结构或算法框架就是稳答题如果想了2分钟还没思路果断标记为难题先跳过。等到所有稳答题都AC了回头再啃难题哪怕只过了部分测试用例也有保底分。5.3 复盘比刷题更重要建立错题本与模板库很多人刷题量很高但笔试成绩仍然不理想原因在于刷题时缺乏复盘。每道题AC后建议花5分钟思考三个问题这道题的核心考点是什么我在哪里卡住了有没有更优的解法把答案记录在错题本中每周集中回看一次。同时建立自己的模板库把KMP、堆优化的Dijkstra、01背包、LIS、并查集、快速幂、二分模板、单调栈模板等高频算法代码整理成文档。到了笔试现场虽然不能翻文档但默写一遍模板能显著减少细节错误。5.4 针对快手B卷风格的专项建议如果说前面讲的都是通用算法那么针对快手这套B卷还有几个特殊的得分点值得强调。一是线段树与树状数组这类高级数据结构B卷考到的概率不高但一旦考到就是拉开差距的题。如果你的目标不是过笔试而是拿高分建议把树状数组的单点更新、区间查询模板吃透它比线段树更短写起来不容易错。二是位运算。B卷偶尔会出一些脑筋急转弯式的位运算题比如找只出现一次的数字计算二进制中1的个数。这类题靠的不完全是刷题量而是对异或、与、或运算性质的敏感度。建议把常见位运算技巧整理成一张速查表异或性质x ^ x 0x ^ 0 x交换律、n (n-1)可以去掉最低位的1、x (-x)可以取出最低位的1。三是对大数据题的敏感度。如果题目中出现了10^9次操作海量数据一定时间内完成等字眼通常不是让你模拟过程而是在暗示需要预处理、二分、或者哈希映射。这类题在B卷里出现频率不高但一旦出现区分度极高。6. 从笔试到面试如何把卷面表现转成机会笔试通过后面试官拿到的不只是你的分数还有你在每道题上的时间消耗。快手面试官常用的一套逻辑是看你在某道题上花了多长时间如果基础的链表题花了40分钟即使AC了面试也会侧重考察你的数据结构基础。如果难题花了大量时间但没AC反而会因为你敢于挑战难题留下好印象。所以在笔试时尽量在简单题上表现出速度和准确度在难题上表现出思考深度和尝试过程。如果一道题完全没思路不要留白至少写一个暴力解法上去说明你有兜底能力。牛客网的判题系统按测试点给分部分正确也能拿分空着才是真正的0分。另外笔试结束后不要马上放松趁热打铁把每道题重新想一遍尤其是那些因为边界条件没AC的题。不要骗自己我理解了只是没时间写了笔试中的错误往往会在面试手撕代码环节原形毕露。我个人在实际操作中的体会是快手B卷这类笔试本质上考的不是天赋而是熟练度。只要你对常见算法模板了如指掌能在读题后快速分析出考点和复杂度就已经超过了80%以上的候选人。剩下的就是心态和细节把每一次笔试都当成一次调试自己学习体系的机会刷题数量不重要重要的是每一题你都吃透了为什么这样写、边界在哪、能不能变通。最后再分享一个小技巧笔试前一周把KMP的next数组、快速排序的partition过程、堆排序的down/up操作、Dijkstra的松弛逻辑、并查集的路径压缩这五件事手写一遍。不需要多每天写一遍即可考试时你会发现这些基础操作会像肌肉记忆一样自动浮现真正帮你节省时间的不是刷了多少新题而是这些烂熟于心的底子。