尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

B站2019秋招算法岗笔试题复盘:从KMP到动态规划核心考点

B站2019秋招算法岗笔试题复盘:从KMP到动态规划核心考点 说实话看到“哔哩哔哩2019秋招技术岗算法第一套笔试题”这个标题我第一反应是有点怀念。那会儿视频社区类的互联网公司正值扩张期算法岗的笔试题目已经比前两年难了一个档次而B站的题目风格一直比较“杂”——既有硬核的数据结构和算法编码题也有不少机器学习基础题偶尔还会冒出几个偏门的选择题。我当时投的是算法工程师岗位收到笔试链接后老老实实刷了三天LeetCode结果还是被几道题卡住了思路。现在回头看这套题的价值其实不在于让你“背答案”而在于它很典型地反映了当时互联网公司对算法岗候选人的核心要求基础扎实、编码熟练、能快速理解问题场景并转化为算法方案。这篇文章我就以亲历者的视角把当时那套笔试题的核心考点、解题思路和踩过的坑完整复盘一遍。内容会比较细从选择题到编程题都会覆盖同时会把每一道题背后考察的知识点和对应的应急解法讲清楚。如果你正准备互联网公司的算法岗笔试或者单纯想看看B站的出题风格这篇文章都值得你花半小时读完。1. 整体印象这套题到底在筛选什么样的人当时我拿到这套题的第一感受是时长90分钟题量不算大但覆盖范围极广。整套题大概分成三块选择题、简答题、编程题。选择题大概10道左右里面对早几年经典的数据结构题和机器学习概念题都有涉及简答题一般是让你简述某个算法的原理或者推导过程编程题则是两到三道手写代码题需要在本地编辑器里完成并提交。从筛选逻辑来看这套题并不是单纯考“你会不会写某道LeetCode原题”而是想看你在有限时间内能不能稳定输出基础算法能力。B站的算法岗偏推荐、视频理解、弹幕分析等方向所以对字符串处理、文本匹配、时间序列类的算法考察会多一些对纯数学推导的考察反而没那么深。我身边有不少同学栽在了一个共同的点上时间分配不合理。前面选择题和简答题花太多时间咬文嚼字导致后面编程题写一半没调通。所以如果你打算投这类公司我建议先快速扫一遍整张卷子把能拿的分先拿到编程题哪怕只能过部分测试用例也能争取到不少印象分。1.1 从热搜词反推考察重点这里有个很有意思的细节。在我复习和搜索相关资料时发现和这套题关联度最高的热搜词集中在几个方向KMP算法、排序算法、粒子群算法、机器学习算法、数据结构。这和B站算法岗的日常工作是能对上的——推荐系统需要处理海量行为序列搜索和弹幕匹配需要高效的字符串匹配排序更是无处不在。所以这套题里出现KMP的next数组计算我完全不意外。另外像“哔哩哔哩视频下载”“哔哩哔哩免费高清视频下载工具”这类搜索词虽然看起来和笔试题没关系但它们背后其实对应了视频内容分析和版权保护等业务场景我猜测这也是B站在算法岗面试时可能延伸追问的方向。笔试通常只考通用基础但如果你能提前了解公司业务在简答题里适当结合场景会是一个加分项。2. 选择题核心考点数据结构与算法基础这一部分我不想逐题罗列毕竟题目版本可能有差异而是把当年几乎必考的几类知识点做个深度拆解。你会发现这些考点非常经典现在很多公司的笔试题依然在考。2.1 KMP算法的next数组计算别靠死记硬背我记得选择题里有一道让你计算模式串pabacaba的next数组。当时很多人直接在草稿纸上画了半天最后还画错了。KMP的next数组本质上是最长公共前后缀的长度但不同教材对next数组的下标定义有差异有一类定义是next[i]表示模式串前i个字符组成的子串中最长相等前后缀的长度。以abacaba为例手动计算过程是这样的i0约定next[0] -1或0视具体定义而定i1子串a没有真前后缀next[1]0i2子串ab前缀a后缀b不相等所以next[2]0i3子串aba前缀a与后缀a相等长度1next[3]1i4子串abac最长相等前后缀为0a与c不等next[4]0i5子串abaca前缀a与后缀a相等长度1next[5]1i6子串abacab前缀ab与后缀ab相等长度2next[6]2i7完整串abacaba最长相等前后缀是aba长度3next[7]3。这样算出来的数组是[-1,0,0,1,0,1,2,3]采用next[0]-1的版本。这里有个容易错的地方计算最长相等前后缀时前缀和后缀不能取整个子串本身必须真前缀和真后缀。很多人会把aba的next算成3就是因为把整个串当成了自己的前后缀。提示笔试时如果遇到next数组建议先用一个简单例子验证自己的定义比如aaaa的next是[-1,0,1,2,3]对应长度版为[0,1,2,3]和“最长相等前后缀长度”完全对应。确认定义后再套到目标串上不要凭记忆硬写。2.2 排序算法的时间复杂度和稳定性B站喜欢考排序因为推荐、排行榜、内容审核里到处都是排序。选择题经常给出几个排序算法的比较让你判断哪个不稳定、哪个平均复杂度最低。考察的表格我整理在这里背熟基本不会丢分排序算法平均时间复杂度最坏时间复杂度空间复杂度稳定性冒泡排序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²)O(n²)O(1)稳定希尔排序O(n^1.3)O(n²)O(1)不稳定选择排序O(n²)O(n²)O(1)不稳定我当时被问到一个经典陷阱题“对单链表进行排序以下哪个排序算法最合适”很多人会选快速排序但链表随机访问困难快排效果不好归并排序因为只需要顺序访问且能保证稳定通常更适合链表。如果能答出“对链表用归并排序利用快慢指针找中点”这题就是送分题。2.3 指针、数组与内存布局“数组和指针笔试题”是热搜词里出现的一项。C/C背景的同学可能比较熟但很多Python选手在遇到这类题时会懵。其实这类题核心就是考察指针运算和数组退化的概念。比如int a[5] {1,2,3,4,5}; int *p a; printf(%d, *(p3));输出是4因为p3指向数组下标3。这里容易混淆的是a1和a1a1是第二个元素地址而a1会跨过整个数组偏移5个int。这类题在选择题里属于“快速拿分”的题只要记住“数组名在表达式中会退化为首元素指针但sizeof和例外”就行。2.4 图论与贪心算法的选择题套路B站笔试还出现过Dijkstra算法、二分图匹配相关概念。不过选择题一般不会让你手写完整算法而是让你判断某个说法是否正确比如“Dijkstra算法不能处理负权边”“贪心算法不一定得到全局最优解”。这些判断题只要理解核心原理就很简单。3. 机器学习与算法原理简答题从粒子群到深度学习简答题是整套题里最能拉开区分度的部分。因为选择题可以蒙简答题必须写出思路。我回忆中有几道题非常经典首先是“粒子群算法原理”。很多做传统算法的人可能没接触过但B站既然考了说明他们希望候选人具备比较广的知识面不只是会调包。3.1 粒子群算法的核心公式怎么答粒子群算法PSO模拟鸟群觅食行为每个粒子代表解空间中的一个候选解通过个体历史最优和群体历史最优来更新自己的速度与位置。核心更新公式速度更新v[i] w * v[i] c1 * rand() * (pbest[i] - x[i]) c2 * rand() * (gbest - x[i])位置更新x[i] x[i] v[i]其中w是惯性权重c1和c2是学习因子rand()是[0,1]之间的随机数。我在答这道题时还额外写了“通常w从0.9线性递减到0.4前期侧重全局搜索后期侧重局部收敛”这属于实操经验阅卷人看到这种细节会认为你是真的用过而不是单纯背公式。经验简答题里写公式时一定要把每个符号的含义解释清楚千万别只扔一个公式上去。面试官想看到的是“你理解这个过程”而不是“你记忆力好”。3.2 机器学习基础LR、SVM、树模型简答题还经常考逻辑回归LR和支持向量机SVM的区别。答题思路可以从损失函数、目标函数、决策边界、处理非线性能力等方面切入。LR用交叉熵损失SVM用合页损失并带间隔最大化LR天然给出概率输出SVM输出的是距离LR对异常值相对敏感SVM因为有支持向量机制鲁棒性稍好。树模型如GBDT、XGBoost也是高频考点。如果题目问“随机森林和GBDT的区别”可以从并行与串行、降低方差与降低偏差、样本采样与全量训练等角度回答。如果能补充一句“XGBoost在目标函数里加入正则项并对损失函数做了二阶泰勒展开”会比单纯说“GBDT用梯度提升”得分更高。3.3 深度学习CNN和RNN的考察方向算法岗肯定会涉及到深度学习。当时有一道题是“卷积神经网络中感受野怎么计算”公式是RF[i] RF[i-1] (kernel_size - 1) * stride_stride_accumulated简化理解从最后一层往前推每经过一个卷积核大小为k、步长为s的层感受野会按(k-1)*s扩大。我还遇到过“LSTM为什么能缓解梯度消失”的简答答案是引入了门控机制和细胞状态让梯度可以在时间步之间以接近1的系数传递。4. 编程题实战三道必须拿稳的经典题编程题是这套笔试的压轴也是我当年花时间最多的地方。虽然题目细节记不全了但核心题型基本跑不出下面这几类。每一类我都整理了可以直接改写的代码模板和易错点。4.1 最长回文子串中心扩展法是最稳的选择判断一段文字里有没有回文、找最长的回文片段在弹幕情感分析、评论纠错里都会用到。所以“最长回文子串”这类题出现频率极高。LeetCode第5题就是原题。笔试环境下我建议优先写中心扩展法因为它的实现简单、不易出错时间复杂度O(n²)在笔试数据规模下通常够用。def longestPalindrome(s: str) - str: if not s: return start, end 0, 0 for i in range(len(s)): len1 expandAroundCenter(s, i, i) # 奇数长度回文 len2 expandAroundCenter(s, i, i 1) # 偶数长度回文 length max(len1, len2) if length end - start 1: start i - (length - 1) // 2 end i length // 2 return s[start:end1] def expandAroundCenter(s, left, right): while left 0 and right len(s) and s[left] s[right]: left - 1 right 1 return right - left - 1注意事项中心扩展法一定要分别处理奇偶两种情况很多人只写了一种导致偶回文串全部漏掉。别忘了最后返回子串时下标的计算start i - (length - 1) // 2这个公式可以在现场推导一下别背错。4.2 最大子序和一句DP口诀记一辈子“最大子序和”也是常客。这道题对应LeetCode 53题在B站笔试里出现我一点不奇怪因为很多业务指标都涉及“找一段最优区间”。它的状态转移方程非常简单dp[i] max(nums[i], dp[i-1] nums[i])含义是以i结尾的最大子数组和要么自己单独成段要么接到前面的段后面。最终答案是所有dp[i]的最大值。代码如下def maxSubArray(nums): dp nums[0] ans dp for i in range(1, len(nums)): dp max(nums[i], dp nums[i]) ans max(ans, dp) return ans这里有个大多数人会踩的坑不能只用一个变量记录当前和还要维护全局最大值。如果你只输出最后一个dp那就会在数组后面出现负数时得到错误答案。4.3 买卖股票的最佳时机状态机思路完胜暴力算法岗笔试里“股票买卖”系列题属于送分题但很多人一紧张就直接双重循环复杂度爆表。笔试里最常考的是只有一次交易的情况也就是LeetCode 121题。解法核心是遍历价格时维护“之前的最小价格”和“当前能获得的最大利润”。def maxProfit(prices): min_price float(inf) max_profit 0 for price in prices: if price min_price: min_price price elif price - min_price max_profit: max_profit price - min_price return max_profit如果题目升级为“不限交易次数”那就用贪心只要今天比昨天价格高就累加差值。B站的题目一般不会直接考太难的股票问题但懂得这两个版本基本就能应对。4.4 编辑距离经典动态规划务必手写出来编辑距离计算的是两个字符串互相转换需要的最少操作数在视频字幕匹配、文本查重、用户输入纠错里都有应用。这也是很有区分度的一道动态规划题如果能完整写出来会让面试官对你的编码能力更放心。转移逻辑是dp[i][j]表示word1前i个字符到word2前j个字符的编辑距离。如果word1[i-1] word2[j-1]则dp[i][j] dp[i-1][j-1]否则在插入、删除、替换三种操作里取最小值加1def minDistance(word1, word2): m, n len(word1), len(word2) dp [[0] * (n 1) for _ in range(m 1)] for i in range(m 1): dp[i][0] i for j in range(n 1): dp[0][j] j for i in range(1, m 1): for j in range(1, n 1): if word1[i-1] word2[j-1]: dp[i][j] dp[i-1][j-1] else: dp[i][j] min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) 1 return dp[m][n]注意DP表的初始化空串到任意串的距离就是字符串长度这个忘记初始化会导致整个表错乱。编辑距离的空间复杂度还可以优化成一维数组但在笔试环境下先写二维DP正确性优先。5. 避坑手册笔试现场最容易犯的五个错误这部分是我最想分享的实战经验。我在好几场笔试里都吃过亏整理成一张速查表希望大家别再踩我踩过的坑。5.1 时间分配不当前面选择题30分钟简答题30分钟编程题30分钟是当年比较合理的时间配比。但很多人会在选择题的某道偏题上纠结10分钟最后编程题没时间调。建议遇到不会的选择题先标记跳过等所有会的题做完再回头猜。5.2 不仔细读题导致题意理解偏差B站笔试题的题干有时候会故意加一些限制条件比如“要求时间复杂度O(n log n)”“不能用额外空间”“输入可能包含空格”。我当年有一道编程题要求处理带空格的字符串我没注意结果用input().split()直接把空格吞了样例过了隐藏测试全挂。所以读题至少要读两遍重点关注输入输出格式和复杂度要求。5.3 边界条件考虑不全边界条件是最容易翻车的地方空数组、字符串长度为1、全是负数、目标值不存在、链表为空。建议写完代码后手动跑一遍最小用例。比如最长回文子串先跑空串再跑单字符再跑aa这几个用例能快速暴露大部分问题。5.4 编程语言API不熟练很多同学用的是Python但笔试平台上Python的版本和本地环境可能有差异。比如input()读取速度慢数据量大时可能超时。如果数据规模上百万建议用sys.stdin.readline()。另外python的递归深度默认是1000如果写DFS用递归深度超过1000就会栈溢出这时要改成迭代或增加递归限制。5.5 提交前没有做自测笔试平台一般允许你写测试用例跑一下但很多人提交前只是看样例通过就交了。我的习惯是写两三个额外用例包括边界情况在本地先跑通再粘贴到平台。有一个笨但很有效的方法把自己的代码复制到本地IDE用随机小数据和暴力解法对比输出。笔试时间够的话这种方法能抓住很多隐藏bug。6. 深度复盘这套题背后隐藏的能力模型刷完这套题我的最大收获不是背会了几个算法模板而是理解了B站这类公司到底想要什么样的算法工程师。笔试背后其实有一套能力模型我用简单的分类来说明。6.1 基础编码能力笔试的编程题主要看你能不能把思路快速转换成实际可运行的代码。它不需要你写出工业级代码但需要变量命名清晰、逻辑分支完整、边界条件周全。这个能力没有捷径唯一有效的提升方式就是每天刷题并且是“限时刷题”。我当时给自己定的计划是每天两道LeetCode中等题控制在40分钟内一个月后手写代码的速度明显提升。6.2 算法选型能力同样的一个问题可以用不同算法解决但复杂度差异很大。笔试题就是考察你能不能根据数据范围选对算法。比如看到n 10^5O(n²)基本就是超时就应该优先想二分、堆、哈希、双指针、动态规划这类O(n log n)或O(n)的做法看到n 20可以考虑状态压缩、回溯。这套选择题里的排序、KMP其实就是在考察你知不知道“什么时候用什么”。6.3 理论联系实际的能力简答题里的粒子群、机器学习原理看起来和笔试当天的业务无关但B站作为一个内容和社区平台每天要面对推荐排序、弹幕去重、视频分类、用户风控这些问题背后全是这些算法的变体。如果你能在简答题里主动举一个和视频网站相关的例子比如“用粒子群算法优化推荐排序中的权重参数”一定会让阅卷人眼前一亮。7. 写在最后这套题能带给你的不只是工作机会我记得当时在网上搜“哔哩哔哩2019秋招技术岗算法第一套笔试题”时能找到的回忆版很少很多人只会说“很难”。但冷静下来复盘这套题的难度其实处于大厂笔试题的中等水平它不追求用偏题怪题难倒你而是把最核心的基础知识融进场景里看你能不能稳定输出。如果你也准备投B站或其他互联网公司的算法岗我个人的建议是不要只刷LeetCode热题一定要把KMP、排序、二叉树、动态规划、机器学习基础这些知识的原理吃透。笔试只是第一关之后的面试会更深入地追问你看似“会了”的知识点。只有把底层逻辑弄明白你才能在各种形式的考察中都站得住脚。最后再分享一个实操小技巧每做完一套笔试题不管有没有通过都花半小时把每道题的知识点、错误原因、最优解法整理到自己的错题本里。我当时整理了厚厚几十页很多面试时被问到的题恰恰是我在笔试复盘时总结过的内容。准备面试没有捷径但复盘和积累绝对是最值得投入的一条路。
返回列表