ARTICLE DETAIL

资讯详情

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

百度Java秋招笔试复盘:考点解析与避坑指南

百度Java秋招笔试复盘:考点解析与避坑指南 2024年秋招我在9月中旬参加了百度的Java工程师第二批笔试。投的是后端开发岗从网申到收到笔试通知大概隔了一周节奏比预想中快。说实话百度的笔试在互联网大厂里属于难度中等偏上的水准客观题覆盖面广编程题也不是送分题两个多小时的考试里要完成30道左右的选择题和3道ACM模式的算法题整体压力并不小。这篇内容不做平台化宣讲纯粹从我个人角度把这次笔试的题型分布、考点深度、做题策略和踩过的坑完整复盘一遍给正在准备Java后端秋招的同学一个真实参考。1. 笔试全流程复盘从投递到上机1.1 第二批笔试的时间线与投递节奏我2024年8月底在百度招聘官网投递了Java工程师岗位选择的是后端开发方向。投递渠道用官网还是内推都行但这里要提醒一下内推不等于免笔试该走的流程一步也不会少只是简历筛选阶段可能稍微有点优势。投递后大概一周左右我收到了第二批笔试邮件通知。邮件里会写明笔试时间、考试时长、考试平台和注意事项。百度的笔试批次是按简历投递时间分流的首批和第二批的考试内容大概率不同但考察范围基本一致。我参加的是第二批安排在9月下旬的一个工作日晚间考试时长两个半小时。这里有个很关键的细节收到笔试邮件后一定要第一时间点击“确认参加”。有些同学会漏掉这个步骤虽然系统在超时后会自动安排但手动确认一下更稳妥。另外邮件里通常会附带模拟笔试链接强烈建议在正式笔试前花10分钟走一遍模拟环境不然后面在真实考场上很容易被监考系统的提示搞得手忙脚乱。1.2 线上笔试环境与题型分布百度的线上笔试用的是在线OJ平台考试全程开启摄像头监考屏幕也会被录制。这意味着考试不能切出页面即便切出去查个JDK API都会被记为异常。考前我专门检查了网络、摄像头、浏览器版本建议尽量用Chrome或者Edge用老版本浏览器很容易出现白屏或提交失败的问题。考试题目分三大块单选、多选和编程题。我这场笔试的整体分布差不多是这样题块数量分值占比建议时间单选20道左右约40%25分钟多选8道左右约15%15分钟编程题3道约45%60分钟客观题覆盖了Java基础、集合框架、JVM、并发编程、Spring、MySQL、Redis、操作系统、计算机网络甚至还有两道专门考Linux命令行的题这个考察范围比很多大厂都要宽。编程题则是标准的ACM模式自己处理输入输出难度梯度比较明显第一题属于签到题第二题中等偏上第三题才是真正拉开差距的压轴题。1.3 时间分配策略在2.5小时的考试里时间分配是决定分数上限的关键因素。客观题必须快遇到不会的标记一下直接跳不要在单题上耗超过2分钟。我整体的节奏控制为“客观题40分钟编程题80分钟最后10分钟回过头检查”这样编程题有充足的调试时间不会出现做完了却没时间验证的尴尬情况。编程题的做题顺序也有讲究。见过太多人一上来就死磕最后一题结果卡了50分钟写不出来前面的简单题反而没时间做。正确的做法是先把三道题都通读一遍快速评估难度然后由易到难依次作答。先保证签到题AC再拿中等题的大部分分数最后有余力再碰压轴题。实际考试中第三道题只要能写出暴力解或者部分case能过就已经能甩开一批人了。多选题是另一个容易丢分的地方。百度的多选题如果“少选不得分”意味着你答错一个选项整题就是0分所以心态上一定要稳模棱两可的选项宁可不选拿确定性最高的分数。2. 选择题考点深挖八股文到底考得多细2.1 Java基础与集合框架的送分题与陷阱Java基础题在单选里占了很大比重难度不算大但陷阱不少。比如有一道题让选“关于String的说法正确的是”选项里会有“String是不可变类所以线程安全但StringBuilder线程不安全”这种半对半错的表述很容易看走眼选错。还有一道题考了String.intern()在JDK7之后的字符串常量池行为这个知识点平时开发中用得不多但笔试非常爱考。集合框架几乎是必考点。HashMap底层结构、加载因子为什么是0.75、JDK8之后什么时候链表转红黑树链表长度达到8且数组长度大于等于64、扩容时的高低位迁移规则都是高频考点。我印象里有一道题问“HashMap在并发场景下会出现什么问题”这就是经典的并发安全考题。JDK8之后链表头插改尾插死循环问题理论上被修复了但并发下的数据覆盖和size不准确仍然存在所以正确选项指向ConcurrentHashMap。ArrayList和LinkedList的区别也是经典问题但百度的出题方式往往更绕不是让你直接说区别而是给一段代码判断时间复杂度或者是否抛异常。比如subList返回的是视图而不是新List修改原List后访问subList会抛ConcurrentModificationException这种细节才是考察重点。我在准备阶段把集合框架的源码过了一遍尤其是ArrayList的扩容机制、HashMap的put和扩容流程这次笔试帮我省了不少时间。2.2 JVM与并发编程易错题集中营JVM的题覆盖面很广。内存区域划分、堆与栈的区别、对象的内存布局对象头、实例数据、对齐填充、GC Roots的可达性分析这些属于必背内容选择题直接检验记忆是否牢固。有一道题印象比较深一个Java进程的堆内存不断增长最终抛出 java.lang.OutOfMemoryError: Java heap space问你该通过哪些参数和步骤定位问题。这类题在热搜词里频繁出现因为OOM是生产环境最常见的故障之一笔试考察它完全是合理的。垃圾回收器也是考察重点。CMS和G1的区别、G1的Region划分和可预测停顿模型、三色标记和漏标问题考得并不浅。尤其是G1不仅问原理还会结合参数来出题——-XX:MaxGCPauseMillis的停顿目标是在新生代范围内尽量满足而不是绝对保证。这种表述正确与否只有真正理解G1内部机制的人才能准确判断死记硬背很容易被迷惑项带跑。并发编程的易错题更是重灾区。synchronized的锁升级过程偏向锁、轻量级锁、重量级锁、volatile的可见性和有序性以及它不能保证原子性、ThreadPoolExecutor的七大参数和四种拒绝策略每个点都能出好几道题。我印象里有一道题考的是线程池核心线程数为5最大线程数为10阻塞队列长度为100提交200个任务最终有多少个任务会被拒绝这道题必须把整个流程算清楚核心线程未满时先创建核心线程执行核心线程满后任务进入阻塞队列队列满后再创建非核心线程直到最大线程数再满才触发拒绝策略。把这条链路理清楚答案就呼之欲出了。2.3 Spring、MySQL与Redis的考察方式Spring框架的考察以原理为主。IOC容器和Bean生命周期几乎必考Bean的构造、属性填充、初始化方法、AOP代理生成整个流程选择题经常会以“下列哪个方法在Bean实例化之后、属性填充之前执行”之类的方式出现。事务传播行为也是高频点REQUIRED、REQUIRES_NEW、NESTED之间的区别特别是NESTED和REQUIRED在回滚范围上的差异很多人说不清。Spring AOP的底层也不只是简单问JDK动态代理和CGLIB的区别而是直接给一个场景做判断比如“目标类没有实现任何接口用JDK动态代理会不会报错”。这就是实际开发中会踩到的坑没有真正写过、调过错的同学很容易选错。MySQL的部分主要围绕索引和事务展开。B树索引结构、聚簇索引与非聚簇索引、最左前缀法则、回表问题这些是必背内容。事务的ACID特性、隔离级别、MVCC的原理undo log ReadView也基本是标配。有一道题问“在可重复读隔离级别下一个事务里的两次范围查询结果为什么可能不一致”其实就是MVCC的间隙锁和当前读、快照读之间的区别。把这块真正理解透不仅笔试能得分面试也能用上。Redis的考题集中在缓存三兄弟——缓存穿透、缓存击穿、缓存雪崩以及各自的解决方案。此外还涉及持久化机制RDB和AOF的优缺点对比、AOF重写的触发条件。分布式锁也是一个考点用Redis实现分布式锁时SETNX EXPIRE的原子性问题、Redisson看门狗机制的实现原理这些在Java面试八股文里都是妥妥的大热门。2.4 多选题不确定就少选的得分策略多选是这次笔试里最难的一环没有模棱两可的空间多选一个选项就是整题零分。我的策略很简单只选100%确定的选项只要有一个选项不确定宁可少选也不要冒险。能拿到一部分分数比全错要划算得多。这种策略看似保守但在计分规则苛刻的考试里稳定得分才是最优解。多选题的考点也会刻意往冷门方向偏。我记得有一道题考了Java运算符和表达式看起来简单但把位运算符、短路求值、自增自减的前置后置混合在一起很容易把答案选漏。还有一道考Java枚举类型的使用int常量与枚举的对比、枚举的values()方法、枚举线程安全问题准确率并没有想象中高。这类题平时很少专门复习完全靠基础功底硬扛。3. 编程题实战ACM模式下的三个解题思路3.1 第一题滑动窗口求最长无重复字符子串第一道编程题是签到难度题目是给一个字符串找出其中不含重复字符的最长子串长度。这题在LeetCode上是第3题属于很典型的双指针哈希表思路。我扫了一眼大概就知道怎么做但真正写起来有几个细节考验人。我的做法是用HashMap记录每个字符最近一次出现的下标维持一个左边界left和一个右边界right每次遍历到重复字符时把left更新为重复字符上次出现位置的下一个下标。这里有个大坑left在更新时不能直接取map里的旧值而要取Math.max(left, 旧下标1)否则可能出现left回退的问题这在“abba”这类用例上会直接算错。import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) throws Exception { BufferedReader br new BufferedReader(new InputStreamReader(System.in)); char[] arr br.readLine().trim().toCharArray(); MapCharacter, Integer map new HashMap(); int left 0, ans 0; for (int right 0; right arr.length; right) { char c arr[right]; if (map.containsKey(c)) { left Math.max(left, map.get(c) 1); } map.put(c, right); ans Math.max(ans, right - left 1); } System.out.println(ans); } }代码本身不难但有几个容易踩的细节第一用BufferedReader而不是Scanner读输入字符串可能很长Scanner的next()在数据量大的时候明显更慢第二字符串处理时trim()一定要加不然某些平台上读进来会带换行符第三HashMap里put的时机也很关键必须先判断再put否则重复字符的旧下标被覆盖后left就无法正确更新了。3.2 第二题课程表与拓扑排序第二题是典型的拓扑排序题目大意是给定课程数量和先修关系数组判断能否完成所有课程。这道题其实就是LeetCode 207的原型。百度考它的原因很明确图论在实际开发的依赖管理中应用广泛而且拓扑排序的思路在Spring Bean初始化顺序里也有体现属于“学了就能用”的经典算法。我的实现思路是建入度表和邻接表用队列做BFS。先把所有入度为0的节点入队然后依次弹出节点将其所有后继节点的入度减1如果减到0就入队。最后判断被处理的节点数量是否等于总节点数不等于则说明存在环无法完成全部课程。import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.*; public class Main { public static void main(String[] args) throws Exception { BufferedReader br new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st new StringTokenizer(br.readLine()); int n Integer.parseInt(st.nextToken()); int m Integer.parseInt(st.nextToken()); ListListInteger graph new ArrayList(); int[] indegree new int[n]; for (int i 0; i n; i) graph.add(new ArrayList()); for (int i 0; i m; i) { st new StringTokenizer(br.readLine()); int x Integer.parseInt(st.nextToken()); int y Integer.parseInt(st.nextToken()); graph.get(x).add(y); indegree[y]; } QueueInteger queue new ArrayDeque(); for (int i 0; i n; i) { if (indegree[i] 0) queue.offer(i); } int cnt 0; while (!queue.isEmpty()) { int cur queue.poll(); cnt; for (int next : graph.get(cur)) { indegree[next]--; if (indegree[next] 0) queue.offer(next); } } System.out.println(cnt n ? 1 : 0); } }这道题有两个坑值得注意。第一是输入格式题目给的是n个节点m条边的形式先读n和m接下来m行每行两个数有些同学没看清把行列顺序写反处理过程直接乱套第二是课程编号可能从0开始也可能从1开始做题前一定要从样例输入里确认清楚不然数组下标越界是最典型的报错。3.3 第三题动态规划与状态压缩的压轴第三题是一道状态压缩动态规划题目大意是在一个矩阵中挑选若干单元格要求相邻的格子不能同时选求最大价值。这种“不相邻选择”的模型在算法竞赛里很常见用状态压缩DP处理网格类问题是很经典的套路但在笔试现场能快速想出来的人并不多。思路是对每一行用一个二进制掩码来表示选中状态掩码中为1的位置表示该列被选中。先枚举当前行的所有合法状态不能有相邻的1再枚举上一行的所有合法状态如果两行状态在同行列上没有冲突就做状态转移。dp[row][state]表示处理到第row行且该行状态为state时的最大价值。// 以leetcode 213. 打家劫舍II 的变体形式为例这类题通用框架如下 public int rob(int[] nums) { int n nums.length; if (n 1) return nums[0]; return Math.max(robRange(nums, 0, n - 2), robRange(nums, 1, n - 1)); } private int robRange(int[] nums, int start, int end) { int pre 0, cur 0; for (int i start; i end; i) { int tmp cur; cur Math.max(cur, pre nums[i]); pre tmp; } return cur; }这个题要做完整的状态压缩DP实现会比较长笔试时如果时间不够有一个取巧的路线前几个测试样例通常比较小直接暴力回溯DFS去跑也能拿一部分分。ACM模式下的OJ一般是按通过的数据点给分能过一部分case就能得一部分分数所以遇到压轴题不要直接放弃先把暴力版本写出来能拿一分是一分。3.4 输入输出与极端case笔试里的隐形得分点编程题最惨的不是不会做而是思路对了但输入输出格式不对导致通过率0%。我这次笔试就差点在这上面翻车。ACM模式的OJ对输出要求极其严格不要输出多余的空格和换行每条结果单独一行类名必须是Mainmain方法签名不能写错。百度的题目没有特殊要求时一律用标准输入输出不需要涉及文件读写。还有一个容易被忽略的点整数溢出。这类题目的数据范围经常到10^9以上两个数相乘可能直接超int范围用long声明变量是最保险的做法。另外Java里的Integer.parseInt处理空字符串会直接抛NumberFormatException如果使用readLine读取记得先判断是否为null或空串。这些细节在本地IDE里很难暴露但上了OJ就是生死线。4. 复盘与避坑指南从环境配置到笔试心态4.1 笔试环境的坑我踩过的三个雷笔试环境的问题是最不该发生的丢分点但我在这里踩了不少坑写出来给各位避雷。第一个雷是浏览器兼容性。考试平台对摄像头权限要求很高我第一次用某个老版本的浏览器进入考试页面摄像头一直黑屏折腾了十分钟才换浏览器解决。建议考前一定在模拟环境里完整测一遍而且最好准备一个备用浏览器Chrome和Edge都装上哪个有问题能立刻切换。第二个雷是网络稳定性。笔试过程中有一次我的网络波动了一下答题页面弹了个“网络连接异常”的提示当时把弹窗关掉继续做题但后来发现有几道已经选择的答案可能没有及时上传成功。这个教训告诉我网络不稳定的前提下不要一次性把所有答案拖到最后统一提交每做完一题就立即保存一题。第三个雷是考试过程中的误操作。笔试平台为了防作弊会锁定页面但如果误触了浏览器的刷新快捷键会弹出确认框处理不好可能直接白屏。好在系统有自动保存机制重新进入后能恢复之前的答题记录但浪费的时间是实实在在的这些时间本来可以用来检查编程题的边界条件。4.2 常见异常与排查思路速查我把笔试过程中容易遇到的异常整理成一个速查表给各位一个参考异常现象可能原因处理建议本地运行正常OJ通过率0%类名不是Main、输入输出格式不符检查类名、换行符、是否有多余空格程序提示内存超限递归过深、数组申请过大递归改迭代数组大小根据数据范围精确计算编译错误漏import、JDK版本差异尽量用JDK8语法避免使用太新的API部分case超时算法复杂度过高、Scanner读取慢换BufferedReader、复杂度从O(n^2)降到O(nlogn)死循环或数组越界while循环缺少终止条件、边界判断缺失加break语句、逐边界条件检查这些异常里最气人的就是“本地运行正常OJ通过率0%”。遇到这种情况第一反应不要怀疑代码逻辑先检查输入输出格式。OJ的判定系统是黑盒的它只看输出字符串是否与标准答案完全一致多一个空格都不行。记住ACM模式下System.out.println自带换行不需要再手动加\n。4.3 笔试后的复盘动作不只是等结果笔试结束不等于万事大吉。我会在考试结束后趁记忆还算清晰把笔试涉及的知识点列一个清单把没有把握的题记录下来逐个查漏补缺。百度的笔试内容其实和面试的考察方向高度重合特别是Java基础、JVM、Spring、MySQL这些热点笔试里的重点在面试里还会以更具深度的方式出现所以把笔试中的错题做成笔记能直接为后续面试做准备。比如这次笔试中有一道题涉及到Spring循环依赖的三级缓存和Bean生命周期我复习时把三级缓存机制重新梳理了一遍反复手写了singletonFactories、earlySingletonObjects和singletonObjects三个Map的存取流程。这种复盘式的学习比一路背八股文有效得多因为你知道哪块是自己的弱点可以针对性补强。后续面试中如果再被问到类似问题就能比较流畅地把完整流程讲清楚。关于笔试的备考节奏我再多说一句。笔试前一周不要再去啃新知识把已经掌握的八股文过一遍把常用的算法模板排序、二分、双指针、滑动窗口、拓扑排序、动态规划默写一遍就够了。临时抱佛脚去背红黑树的详细旋转过程没有意义不如把常见套路练熟保证见到题能快速反应。最后再分享一个小技巧考试时把每道编程题的核心思路先在草稿纸上画出来哪怕是几行伪代码再开始动键盘。我自己吃过“边写边想”的亏最后发现思路不清晰代码越改越乱。多花两分钟理思路远比多写二十分钟的调试代码要高效。这次笔试的编程题能用比较稳定的节奏写完很大程度上靠的就是这个习惯。
返回列表