ARTICLE DETAIL

资讯详情

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

百度2023秋招研发岗笔试复盘:算法与数据结构备考指南

百度2023秋招研发岗笔试复盘:算法与数据结构备考指南 2023年秋招季我坐在电脑前在浏览器里打开百度研发岗的在线笔试页面旁边放着两张草稿纸和一瓶水。两个小时的考试前半段是选择题后半段是编程题答题过程中能明显感觉到这不是单纯刷题就能应付的考试它更像一次综合能力的筛选。考完之后和几个同样参加秋招的同学复盘发现这套题在设计上确实有它的章法——知识点覆盖广、代码题难度递进、选择填空题考察得很细。这篇文章就围绕百度2023年秋招研发岗笔试聊聊我的实际体验、踩过的坑以及事后总结出来的一套备考思路。无论你是正在准备2024届秋招还是想了解大厂研发岗笔试的考察逻辑这篇复盘应该都能给你一些参考。1. 笔试在秋招链路中的定位为什么一份代码卷能刷掉大部分人1.1 简历筛选和面试之间笔试承担的不只是筛人先理清一个容易被低估的问题笔试在秋招整体流程里到底扮演什么角色。投递百度研发岗之后大部分同学会先收到测评或笔试链接。简历筛选自有 HR 和业务线的规则但笔试更像一个标准化考试它的价值在于用同一套题目在同一个时间窗口内横向对比所有候选人。简历里的项目经历可能注水实习经历可能包装但代码题对不对、边界条件想没想到、时间复杂度过不过得去——这些在在线评测系统里一测便知。所以笔试承担的核心功能是卡基准线筛选出代码能力扎实、基础概念清晰、具备基本解题思维的人。我有位同学秋招投了二十多家公司简历关几乎一路绿灯但最后拿到的面试邀请寥寥无几。后来查了下记录发现好几家都是在笔试环节就被沉了。这件事给我最大的提醒是研发岗的简历写得再漂亮笔试不过线后面的一切都无从谈起。1.2 与其他公司笔试题相比百度的出题风格有什么特点横向对比过几家大厂的研发岗笔试题之后我觉得百度的出题风格有几个比较明显的特征。第一难度梯度做得比较清晰。题目不是从头难到尾而是由易到难排列前面的选择题甚至有几道属于送分题比如数据结构基础、排序算法复杂度、TCP 握手过程这类计算机基础知识。这样的设计意图很明显先保证基础扎实的人能拿到基本分再通过后面的编程题拉开区分度。第二编程题注重考察常见算法的灵活变形而不是直接出模板题。直接套模板往往过不了需要根据题目条件做额外处理。第三部分题目带有业务色彩题干可能会包装成搜索、推荐、地图导航这类实际场景本质上就是在考算法但阅读量更大对理解题意能力提出了更高要求。1.3 笔试得分怎么影响后续流程很多人以为笔试只是及格和不及格的区别实际上不是。在百度这类大厂的招聘系统里笔试成绩往往会伴随你的整个面试流程。面试官能在系统里看到你的笔试得分和解题详情甚至能翻看你提交的代码。如果笔试成绩够高面试时你有机会被问到更多加分项问题考察重点也从基础行不行转向潜力大不大如果笔试成绩低空飘过面试官往往会挑着你的弱项往深处问相当于给简历上的技术画像打个底。所以我给所有准备秋招的同学一个建议笔试不要抱着过了就行的心态能多拿一分是一分尤其是编程题尽量做到提交的代码逻辑整洁、注释清晰。有些面试官真会看你的答题代码——我和朋友在面试时就遇到过面试官指着笔试系统里我提交的代码说你这题当时的思路记录挺清楚的来说说为什么用二分而不是哈希2. 卷面拆解考试构成、知识点分布与时间分配的实测复盘2.1 题型构成和大致占比以我实际参加的场次为例整个笔试卷面大致分为三个部分单选题、多选题、编程题。选择题加起来大概占总成绩的一半编程题占另一半。具体分值比例每年可能有调整但大方向不会变——代码能力始终是重头。选择题的内容覆盖范围比较宽这也是很多同学觉得复习不过来的原因。从考点来看主要有这几块数据结构栈、队列、二叉树遍历、散列表冲突处理、堆和优先队列的复杂度算法基础排序算法稳定性、二分查找边界、贪心算法的适用条件、动态规划的判断操作系统进程与线程、死锁条件、虚拟内存、页面置换计算机网络TCP/UDP、HTTP 状态码、DNS 解析过程、拥塞控制数据库事务隔离级别、索引的结构、SQL 的基本写法编程语言特性C 的内存管理、Java 的集合类、Python 的 GIL 这类语言相关的细节这部分没有太多刁钻的题但胜在范围广。如果只看算法题、不看基础概念很容易在这上面丢分。我认识的不少朋友刷题刷得很猛但一到操作系统和网络的选择题就开始犹豫最后笔试成绩被硬生生拉下一个档位。2.2 编程题的难度分布和常用算法编程题一般有 3 道左右难度逐题递增。第一道通常是基础题例如数组遍历、字符串处理或者简单模拟考查的是基本的编码能力确保你能够把思路快速转成代码。第二道会在基础之上加一些弯可能是二分答案、贪心设计、前缀和优化或者经典 DP 的变体。第三道往往涉及图论、搜索、复杂状态 DP 或数据结构组合比如栈加贪心、堆加排序这类复合型题目用来拉高区分度。从算法角度来说以下几类在笔试中尤其需要重点准备二分查找及二分答案尤其是最小值最大/最大值最小这类套路动态规划线性 DP、背包 DP、区间 DP、状态压缩 DP 的经典模型图论搜索DFS、BFS、拓扑排序、最短路径Dijkstra 优先队列版数据结构进阶并查集、树状数组/线段树、单调栈、单调队列字符串处理模式匹配、回文、子串计数2.3 时间分配策略怎么保证选择题和编程题两头兼顾秋招笔试的时间通常是 120 分钟看起来不短但真正分配起来其实很紧张。我的建议是选择题控制在 40 分钟以内绝不超过 45 分钟剩下的时间全部留给编程题。选择题可以用一些快速排除法——分析四个选项的差异点找到关键条件后直接判定不必把每个选项都验算一遍。如果遇到某个知识点确实不熟悉凭第一感觉选一个然后立刻标记跳过千万不要在一道题上死磕五分钟。编程题的时间分配也有技巧。拿到题目后先看一遍三道题的题干大致判断难度从最有把握的那道开始做。哪怕第一题最简单也先花一分钟理清输入输出格式再动手写代码。如果遇到一道题 20 分钟还没有思路果断止损去写其他题最后有时间再回头补。笔试环境里的代码编辑器很朴素没有智能提示写代码的速度和准确率完全靠平时积累所以平时练习时最好直接用命令行或简单编辑器不要过度依赖 IDE。3. 高频考点的底层逻辑为什么笔试偏爱这些知识3.1 数据结构不只考是什么更考怎么选应付百度这类大厂的笔试题数据结构不能只停留在能写出遍历和查找的层面更重要的是理解每种结构的适用场景和复杂度边界。举个例子一道题如果涉及频繁的查询区间最小值和动态修改单个元素你第一反应应该是线段树或树状数组而不是每次查询都重新遍历。因为笔试的测评数据往往会把时间复杂度逼到极限普通做法只能过掉前几个小数据点。又比如括号匹配、表达式求值这类问题天然适合用栈滑动窗口求最值就上单调队列元素去重和快速判断是否存在用哈希表维护前 K 大就用大小为 K 的小顶堆。我看到不少同学在复习时陷入一个误区把每种数据结构的实现代码背得滚瓜烂熟但拿到一个新题时不知道用哪种结构。关键在于场景识别。建议平时刷题时不要只按题目标签刷而是多做不告诉你知识点的题训练自己在题目描述里定位到合适数据结构的敏感度。3.2 动态规划从背模板到定义状态动态规划是百度研发岗笔试里几乎必考的内容要么单独出一道题要么作为编程题里某个部分出现。DP 题的本质是用已知状态推导未知状态核心有三件事状态定义、状态转移方程、边界条件。很多同学觉得 DP 难是因为拿到题之后想的不是我从哪里来或者我能到哪里去而是想套用之前做过的某道题的模板比如这像 0-1 背包我就用背包模板。但大厂的 DP 题往往不是原题。它会在经典模型上做变形可能是物品有额外属性可能是背包容量范围特别大需要剪枝可能是转移时要用到前缀和优化。这时候如果你只记住了模板而没理解状态定义的本质大概率会写出一个看起来对但样例过不了的代码。备考 DP 时更重要的是亲手把每道经典题的转移方程推导一遍弄懂为什么状态数组开这么大为什么初始化是这个值为什么转移顺序是从前到后。理解了这三点遇到变形题才能从容应对。3.3 搜索与图论BFS/DFS 的选择直接影响通过率搜索类题目在百度往年笔试中同样有较高的出现频次。尤其是 BFS 求最短路径、DFS 求连通性和回溯搜索几乎每场都有涉及。BFS 和 DFS 本身不难实现但它们在题目中的应用有一些容易忽略的细节。比如 BFS 求最短步数时除了维护队列还需要一个 visited 数组来避免重复入队否则复杂度呈指数增长。如果图特别大可以考虑双向 BFS 或优先队列 BFS。又比如 DFS 做回溯时撤销状态的顺序和路径选择必须一一对应否则会出现状态污染导致答案错误。这些细节在笔试中特别容易翻车——因为样例数据往往很小你的错误路径可能恰好也能跑出正确结果交给评测机的大数据一测就崩。图论里还需要关注拓扑排序。拓扑排序的应用场景很多判断有向图是否存在环、任务调度、依赖关系问题。它和 BFS 的区别在于利用了入度作为约束条件代码模板很短但很实用建议熟练掌握。Dijkstra 优先队列版本也是常客尤其是当题目伪装成地图导航路线规划这类业务场景时本质上都是最短路问题。3.4 思维题和读代码题防不胜防但可以用系统化方法应对除了算法和数据结构的常规考点百度笔试里偶尔也会出现一些思维题或者读代码题。前者常常以数学技巧、双指针、贪心策略为背景后者则是给一段代码让你判断输出结果、找出 bug 或者分析复杂度。这类题其实并不需要特殊的赛题知识关键是平时养成审题先行、举例验证的习惯。遇到抽象的描述先手写一两个小样例把输入输出跑一遍很多时候答案就自然浮现了。读代码题更是如此。不要盯着代码一行行空想直接在草稿纸上模拟几个输入逐步跟踪变量变化。尤其要注意循环退出条件和变量累加顺序这两处是出题人最喜欢埋雷的地方。4. 在线笔试环境里的实战避坑从输入输出到边界条件4.1 输入输出格式第一只拦路虎在线笔试和本地 IDE 跑代码最大的区别就是输入输出格式完全由题目控制。很多第一次参加笔试的同学会在这一步骤上浪费大量时间。百度笔试系统通常支持多种语言环境以 C、Java、Python 为主评测机会自动调用你的程序把测试数据作为标准输入喂进去校验标准输出。这里最忌讳的就是自己写请输入一个数这类的提示语句评测机会把提示也当成输出的一部分结果全错。多行输入的读取方式也要注意。Python 里常见的坑是input()读取字符串后忘记去掉末尾换行或者用split()切分出空字符串。如果题目没有明确给出数据行数通常需要用while Truetry/except循环读取直到 EOF。Java 里则要注意Scanner的nextLine()和nextInt()混用时的换行问题——建议读完数字后单独再nextLine()一次把残留换行消费掉。C 用cin相对安全一些但要注意getline()和cin混用时的缓冲问题。4.2 样例通过不等于能全过边界条件才是真正的分水岭在线评测系统一般会给一个题目样例样例通过了往往意味着主流程正确但评测数据里还包含大量边界数据空数组、数组长度为 1、全部值相同、值取到 int 上限、负数、字符串长度为 0 等等。这些边界条件才是拉开分数差距的关键。以最大子段和为例如果数组全是负数经典 Kadane 算法的返回值应该是最大的那个负数而不是 0如果初始化max_sum 0就会在全是负数的测试数据上栽跟头。再比如二分查找如果输入数组长度为 1左右指针的初始值和中点计算公式必须保证不越界。这些细节在平时练习时很容易被忽略因为样例通常都是常规数据。考前最后一周刷题时一定要刻意训练自己每写完一个算法就立刻问边界上会发生什么。4.3 时间复杂度与内存限制过了样例却被判超时怎么办笔试系统通常会限制单题时间比如 1 秒和内存比如 256 MB。如果你的解法复杂度是 O(n^2) 而题目给定的 n 是 10^5超时就不可避免。遇到超时最优先的思路是把当前解法的时间复杂度降一个量级。常见的优化手段包括用哈希表把查找从 O(n) 降为 O(1)用排序加双指针替代双重循环用前缀和把区间求和变成 O(1) 查询用二分答案把优化问题转成判定问题用 BFS/DFS 剪枝降低搜索空间。如果代码确实已经优化到最优复杂度但仍然超时那可能是常数太大可以试试关闭同步流C 的ios::sync_with_stdio(false)、用更快的输入输出方式、避免在循环里重复创建对象。内存超限相对少见但一旦出现也很头疼。常见原因是递归深度过大导致栈溢出Python 尤其明显或者数组开得过大却只用了很小一部分。递归过深可以改用显式栈模拟数组过大的话优先考虑滚动数组或状态压缩。4.4 本地运行正常但提交后编译失败语言细节的坑在线笔试的过程里还有一个特别让人抓狂的情况在本地 IDE 里跑得好好的复制到答题框里一提交提示编译错误。常见原因有几个Python 写的代码里用了中文标点或者全角括号Java 的类名没有按系统要求命名为MainC 用了本地特有的头文件或编译器扩展比如bits/stdc.h在某些环境可能不受支持。还有一个很隐蔽的坑代码里用了 Python 3 的语法特性但评测环境是 Python 2 的。提交前一定要留意系统支持的语言版本。5. 编程题复盘三道典型题目从思路到代码的完整推演5.1 典型题一数组区间处理——前缀和 哈希表先来说一道典型的看似简单但很容易超时的数组题。题目大意是给定一个整数数组找出和为某个目标值的连续子数组的个数。最暴力的做法是二重循环枚举所有区间复杂度 O(n^2)如果 n 是 10^5 那么大超时是必然的。正确思路是用前缀和配合哈希表把前缀和存入哈希表在遍历过程中维护当前前缀和减去目标值在哈希表中出现的次数累加进答案。这种题考察的是两个经典技巧的叠加前缀和用于快速计算区间和哈希表用于把是否存在和出现次数的查询降到 O(1)。代码本身很短十几行就写完但如果对前缀和思想不熟可能会在暴力解上浪费大量时间。我当时的做法是用 Python 写的代码如下from collections import defaultdict def subarray_sum(nums, k): prefix_sum 0 count_map defaultdict(int) count_map[0] 1 # 前缀和等于0的情况初始化有助于处理从开头开始的子数组 ans 0 for num in nums: prefix_sum num ans count_map[prefix_sum - k] count_map[prefix_sum] 1 return ans这里最需要注意的就是count_map[0] 1这一行。如果没有它从数组头部开始的子数组会被漏掉。这种细节也是评测数据里最容易藏雷的地方。5.2 典型题二动态规划与空间优化——一维滚动数组第二类高频题是背包类 DP 的变体。比如有一类题目是给定若干物品的重量和价值背包容量为 W求能装下的最大价值。经典 0-1 背包的状态转移是dp[i][j] max(dp[i-1][j], dp[i-1][j-w[i]] v[i])但二维数组在容量很大的时候很浪费空间所以实际答题时通常要改成滚动数组。注意 0-1 背包和完全背包在滚动数组下的遍历顺序完全不同。0-1 背包要求每个物品最多选一次所以内层循环必须从大到小遍历容量完全背包则相反从小到大遍历。很多考生在这里翻车就是因为没理解滚动数组之所以要倒序遍历是为了保证每个物品只被使用一次。代码模板如下def knapsack_01(weights, values, capacity): dp [0] * (capacity 1) for i in range(len(weights)): for w in range(capacity, weights[i] - 1, -1): dp[w] max(dp[w], dp[w - weights[i]] values[i]) return dp[capacity]笔试中遇到这类题千万别急着写代码先在草稿纸上确认这是 0-1 背包还是完全背包物品可不可以重复选容量范围有多大需不需要用位运算或者单调队列优化把这些问题想清楚了再动键盘。5.3 典型题三图上的搜索——BFS 求最短路径的变形第三道编程题通常开始上难度BFS 求最短路径是一个经典的方向。但是笔试题不会那么老实地告诉你求这个图里某点到某点的最短路径长度它会把 BFS 包装成各种场景。比如在一个二维网格里从起点走到终点途中有些格子有障碍物最多可以拆除 k 个障碍物求最短步数。这个题的难点在于同样一个格子拆除不同数量的障碍物后访问它后续状态是完全不同的所以 visited 数组不能只记坐标要记(x, y, 剩余拆除次数)三元组。BFS 的状态设计是图论搜索题的核心。状态设计好了代码就是标准的队列扩散状态设计漏了一个维度答案直接错误。还有一个容易忽略的点是 BFS 的层序问题如果每次循环只弹出一个节点需要记录当前的层深度推荐使用普通队列配合步数数组或者每轮循环通过queue_size len(queue)来逐层处理。以下是我的写法from collections import deque def shortest_path(grid, k): rows, cols len(grid), len(grid[0]) # visited[x][y][k] 记录是否访问过 visited [[[False] * (k 1) for _ in range(cols)] for __ in range(rows)] q deque() q.append((0, 0, k, 0)) visited[0][0][k] True directions [(1, 0), (-1, 0), (0, 1), (0, -1)] while q: x, y, rest, steps q.popleft() if x rows - 1 and y cols - 1: return steps for dx, dy in directions: nx, ny x dx, y dy if 0 nx rows and 0 ny cols: if grid[nx][ny] 0 and not visited[nx][ny][rest]: visited[nx][ny][rest] True q.append((nx, ny, rest, steps 1)) elif grid[nx][ny] 1 and rest 0 and not visited[nx][ny][rest - 1]: visited[nx][ny][rest - 1] True q.append((nx, ny, rest - 1, steps 1)) return -1这道题给我的教训是BFS 的队列里存的信息一定要完整且最小。存了多余信息会浪费内存存少了会导致状态丢失。写完代码后我习惯在本地跑两个用例一个是最简单无障碍的图另一个是所有格子都有障碍物的图专门验证rest的消耗逻辑。5.4 复盘时看的不是答案而是卡住的位置笔试结束后很多人第一件事是找答案对得分。但我更推荐另一个复盘方法找一道当时没做出来的题重新在本地实现一遍记录自己卡住的位置。是理解题意用了太久是状态转移想不到是边界条件没考虑全还是代码 bug 太久没定位出来每一类卡点对应的备考策略完全不一样理解题意慢就多看题、多做长题干模拟状态转移想不到就专门练 DP 和搜索的套路边界条件漏就养成写代码前先列输入输出的习惯。只有把卡点定位准确下一次笔试才不会在同一类问题上浪费时间。6. 笔试之后如何把这份经历转化成面试的竞争力6.1 笔试做得好面试时可以主动利用的机会笔试成绩高在面试环节是有隐形加分的。有些面试官会当场打开你的笔试记录问你这道题当时的思路。如果你能清晰地复述题目、解题思路、复杂度分析甚至指出自己当时代码里的小瑕疵面试官对你的好感会明显上升。这等于你在面试还没开始前就获得了一个相对轻松的技术展示窗口。所以笔试结束后不要立刻把题目忘掉。建议找时间把当时没做出来的题目和做出来但有疑问的题目重新整理成一篇题解笔记。不是为了发博客而是为了面试时能够流畅地讲出来。面试官通常更关注你的思考过程而不是单纯地记忆答案。6.2 根据笔试暴露的薄弱点倒推面试复习优先级笔试结束后对照卷面做一次弱点清单整理很有必要。比如选择题错了操作系统相关的知识点那就把进程管理、内存管理、死锁这些内容重新过一遍编程题卡在 DFS 剪枝上那就集中刷一周搜索类题目读代码题踩了循环条件判断的坑那就多练习手写模拟代码执行过程。笔试暴露的问题通常也是面试时会遇到的问题因为大厂的面试官同样看重计算机基础和数据结构的理解。提早把这些薄弱点补上对后面的面试帮助巨大。6.3 秋招是一个长跑笔试经验是可以复用的百度研发岗笔试带给我的不只是一次通过与否的结果更是一套如何系统备战大厂笔试的方法。这套方法在之后参加其他公司的笔试时也一直在用先拆题型再定时间然后按难度梯度答题遇到卡壳果断跳过最后集中检查边界条件。不同公司的题风格有差异但核心考察的能力是相似的算法思维、编码实现、基础知识的熟练程度。把这些能力练扎实了后面的每一场笔试都会轻松很多。
返回列表