ARTICLE DETAIL

资讯详情

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

京东春招笔试复盘:编程题套路与牛客网避坑指南

京东春招笔试复盘:编程题套路与牛客网避坑指南 2024年春招的京东技术通用岗位第一批笔试我是在牛客网上做的全程两个半小时选择题加三道编程题。当时笔试前我翻了不少面经但真正坐到电脑前才发现光看别人的经验没用得自己把高频考点和平台的机制吃透才行。这篇文章就把我这次笔试的完整复盘写出来包括题型分布、做题节奏、三道编程题的思路推演还有提交之后踩过的那些坑。打算投京东技术岗、或者正在准备其他大厂春招笔试的同学可以拿这篇当个参考。1. 笔试整体设计与考察逻辑1.1 京东技术岗笔试到底考什么京东春招技术通用岗位的笔试虽然岗位名称里写着“通用”但实际考察的覆盖面并不“通用”它想通过一套题筛掉基础不牢和编码能力不过关的候选人。我参加的这场笔试整体结构分为两大部分第一部分是选择题大概20到30道覆盖计算机基础、语言特性、数据结构、网络协议、操作系统、数据库第二部分是编程题一共3道难度梯度区分明显。选择题的内容比我预想的更偏向底层。比如有直接问Java内存模型里volatile关键字语义的有给出一段多线程代码问最终输出结果的还有关于TCP三次握手状态变化的以及MySQL索引失效的常见场景。这些考点单独拿出来都不算超纲但放在同一套卷子里就很考验平时积累的广度。前端方向的同学会额外遇到一两道JavaScript闭包和事件循环的题算法方向则会有概率和数学期望相关的内容岗位方向不同选择题会略有分化。真正决定能否进入下一轮的是编程题。京东的笔试编程题风格比较稳定第一题通常是纯模拟或字符串处理属于白给分第二题是贪心或者排序加双指针需要动点脑子第三题则上升到动态规划或图论的变种用来区分高分选手。我这场的第一题是括号匹配变种第二题是区间合并和最大重叠覆盖数第三题是带状态约束的最短路径问题。整体难度比往年同期略高一点尤其是第三题现场能完整AC的人应该不多。1.2 为什么笔试刷人率那么高评分逻辑是什么大厂笔试刷人率普遍在70%到85%之间京东也不例外。这里面的核心逻辑是笔试阶段投递人数基数极大必须用一套统一标准快速分层把“能做出来”和“能做好”的人区分开。选择题是机器阅卷答案固定不存在任何主观因素编程题则采用部分通过策略也就是会跑你代码通过多少比例的测试用例再按比例给分。京东笔试平台用的是牛客网编程题必须自己处理输入输出语言可以选Java、C、Python中的任意一种但不同语言的复杂度和运行效率直接影响你能过多少测试点。我用的是Java虽然写起来比Python啰嗦但好在运行速度快、稳在第三题超时边缘挣扎的时候不至于因为语言本身的性能问题翻车。关于评测机制有一点特别值得注意牛客的判分是实时反馈的每道题提交后会显示通过了多少测试用例比如“通过3/10”。这意味着你可以做题时先拿部分分把能过的过了再回头优化。很多人做第二题时非要憋一个完美解法结果第一题写错了、第三题没时间看这是非常亏的。正确策略是拿到卷子先把三道题都读一遍心里有数哪些是保底分哪些是冲刺分。2. 题型拆解与高频考点分布2.1 选择题考点分布表我整理了一下这次笔试选择题的大致考点比重下面这个表格是按照我记忆里的题目归属和网上的牛客面经交叉验证过的不同批次可能有波动但方向基本一致。考察方向占比代表题型Java/C语言特性25%volatile语义、构造器执行顺序、引用传递数据结构与算法理论25%二叉树遍历序列推导、哈希冲突处理、堆调整过程计算机网络15%TCP状态迁移、HTTP状态码含义、DNS解析过程操作系统15%进程线程区别、页面置换算法、死锁条件数据库10%B树索引、事务隔离级别、Explain执行计划智力题/概率题10%经典烧绳子、随机数生成、概率期望计算注意这个表格不是官方数据是我结合实战回忆和牛客网上同批次帖子的综合印象。操作系统方向考得不多但很细比如页面置换LRU和FIFO的缺页次数比较这种题只要背过算法逻辑就秒出答案但如果平时只是看书没手算过现场会卡很久。我印象最深的一道选择题是在浏览器输入URL到页面展示中间经历了哪些步骤。这题乍一看是老生常谈但选项里把DNS解析、TCP握手、TLS握手、HTTP请求、浏览器渲染的顺序打乱了还混入了一个“NAT地址转换”和“CDN节点选择”。这种题没有固定套路最好的准备方式就是在脑海中像放电影一样过一遍完整链路每一步都要能说出为什么。2.2 编程题的高频题型池结合京东最近三年春招和秋招的真题来看编程题反复出现的有几个固定方向字符串处理、数组和双指针、贪心、动态规划、图的遍历、二分查找边界。其中贪心考的是“想明白为什么这样贪是对的”动态规划考的是“状态定义和转移方程”图论则通常是Dijkstra的变体或者二维网格上的BFS。字符串处理类题目看起来简单实际最容易失分。比如括号匹配笔试十次里至少出现三次但每次都有细微变化有的要求判断是否有效有的要求计算最少插入次数有的要求输出最长有效括号长度。如果你只背过LeetCode的原题解法没理解栈的弹入弹出时机换一个问法就会卡住。我这次的第一题也是括号匹配但是要求计算删除最少的字符数让括号序列有效本质上就是贪心加栈。再一个高频点是区间问题。合并区间、插入区间、求重叠区间的最大数这类题在京东笔试中出场率极高。原因是它看起来简单但实现层面很容易出现边界条件漏洞比如区间端点相等时算不算重叠。这种“看似简单但藏坑”的题非常适合笔试用来区分“能AC”和“能一次AC”的人。2.3 高频考点背后的考察意图大厂笔试不会平白无故考你某个冷门知识点每一类高频考点背后都有明确的岗位意图。让你做字符串和区间题是考察代码的严谨性因为业务开发中大量工作是处理明文参数、清洗数据、合并配置区间边界条件处理不好就会出线上事故。考动态规划是为了筛选出有建模能力的人遇到一个复杂业务需求你能不能把它抽象成子问题并找到状态转移路径这是高级工程师和普通工程师的分水岭。理解这一点对你备考很有帮助。复习的时候不要单纯刷题每做一道高频题都要问自己这个知识点在真实业务里解决什么问题这样记忆会深刻很多而且面试时如果被追问“你怎么证明你自己的 coding 能力”你可以把笔试题的思路迁移到业务场景中讲故事会非常加分。3. 编程题实操复盘与核心思路3.1 第一题括号删除问题题目大概是这样的给定一个只包含小写字母和左右括号的字符串要求删除最少数量的括号使得剩下的字符串是合法的括号序列。输出删除后的任意一个合法序列。这个问题的正统解法是两次扫描或者栈辅助但如果现场紧张很容易直接陷入“怎么删除最少”这个最优化问题里实际上它并不是DP题。我的做法是这样的用一个栈记录左括号的下标遇到右括号时如果栈为空说明这个右括号是多余的直接标记删除如果栈非空就弹出对应的左括号。第一遍扫描结束后栈里剩下的左括号也是多余的逐个标记删除。最后遍历原字符串把没有标记删除的字符拼起来输出。这个思路的核心在于“删除最少的括号”等于“保留尽可能多的合法括号”。而合法的括号序列天然具有栈结构用栈匹配到的括号对都是可以保留的无法匹配的多余括号才是必须删除的。这个逻辑讲清楚之后代码量非常少。public static String minRemoveToMakeValid(String s) { boolean[] remove new boolean[s.length()]; DequeInteger stack new ArrayDeque(); for (int i 0; i s.length(); i) { char c s.charAt(i); if (c () { stack.push(i); } else if (c )) { if (stack.isEmpty()) { remove[i] true; } else { stack.pop(); } } } while (!stack.isEmpty()) { remove[stack.pop()] true; } StringBuilder sb new StringBuilder(); for (int i 0; i s.length(); i) { if (!remove[i]) { sb.append(s.charAt(i)); } } return sb.toString(); }这里有一个容易踩的坑好多人会用计数器代替栈只记录左右括号数量但这样会丢失位置信息。比如字符串 “(a(b)” 用计数器法会输出 “ab” 或者错误的 “(ab”因为无法知道该删掉哪一个左括号。用栈存下标就能精确定位到需要删除的位置这个细节在题目不要求输出删掉哪些字符而要求输出新字符串时特别关键。3.2 第二题区间最大重叠数题目大意是给出一组区间每个区间有起点和终点求这组区间中重叠最多的区域的覆盖次数。比如 [1,5]、[2,6]、[4,8] 三个区间最大重叠数是3。这道题我会用排序加扫描线处理时间复杂度O(n log n)空间复杂度O(1)如果不考虑存储输入的话。核心思路是建立一个事件列表起点事件带来 1 贡献终点事件带来 -1 贡献。把所有位置排序之后从小到大扫描维护当前覆盖数cur遇到起点就cur遇到终点就cur--过程中取cur的最大值即可。一个细节是区间端点在这里是闭区间还是半开区间如果 [1,5] 和 [5,8] 在端点5处重叠那么事件里同一下标终点事件应该先于起点事件处理否则会多算或漏算。public static int maxOverlap(int[][] intervals) { int n intervals.length; int[][] events new int[2 * n][2]; for (int i 0; i n; i) { events[2 * i] new int[]{intervals[i][0], 1}; events[2 * i 1] new int[]{intervals[i][1], -1}; } Arrays.sort(events, (a, b) - a[0] ! b[0] ? a[0] - b[0] : a[1] - b[1]); int cur 0, max 0; for (int[] e : events) { cur e[1]; max Math.max(max, cur); } return max; }上面代码里排序比较器里先比较位置再比较事件类型把终点事件-1排在起点事件1前面。这里要根据题目对区间重叠的定义调整如果题目说“重叠”指两个区间有公共部分且公共部分长度必须大于0那 [1,5] 和 [5,8] 就不算重叠需要把终点事件排前面先减后加如果题目明确说端点重合也算重叠那终点事件排在后面才对。现场看清题目条件非常关键两种差之毫厘结果谬以千里。这道题还有个变体是求最大的不重叠区间数量。当年牛客上很多人把这两个题搞混了解法完全不一样一个是贪心按右端点排序一个是扫描线。你做题的时候务必先判断清楚题目问的是“重叠覆盖数”还是“最多不重叠个数”这决定了整个解题方向。3.3 第三题带状态约束的最短路径第三题是一道网格图题给定一个二维矩阵每个格子有数值从左上角到右下角要求路径中某一状态的出现次数不能超过某个上限求最短路径或最小代价。这类题在LeetCode上有个原题叫 Shortest Path with Obstacle Elimination核心是用三维visited数组把“当前剩余可穿透障碍次数”作为第三个维度。我的做法是在Dijkstra或者BFS中维护三元组 (x, y, k)k表示走到当前格子时还剩多少次特殊机会。队列弹出的下一步状态如果之前已经用相同的k访问过就跳过否则记录状态并入队。这里不能用二维visited因为同一个格子剩余机会多和剩余机会少是完全不同的状态后者更劣势如果被二维visited覆盖可能会错误跳过更优路径。public static int shortestPath(int[][] grid, int maxSpecial) { int m grid.length, n grid[0].length; if (m 1 n 1) return 0; boolean[][][] visited new boolean[m][n][maxSpecial 1]; Dequeint[] queue new ArrayDeque(); queue.offer(new int[]{0, 0, 0, 0}); // x, y, usedSpecial, dist int[][] dirs {{1,0},{-1,0},{0,1},{0,-1}}; while (!queue.isEmpty()) { int[] cur queue.poll(); if (cur[0] m - 1 cur[1] n - 1) return cur[3]; for (int[] d : dirs) { int nx cur[0] d[0], ny cur[1] d[1]; if (nx 0 || nx m || ny 0 || ny n) continue; int used cur[2] grid[nx][ny]; if (used maxSpecial || visited[nx][ny][used]) continue; visited[nx][ny][used] true; queue.offer(new int[]{nx, ny, used, cur[3] 1}); } } return -1; }这段代码是BFS版本适用于所有边的权重相同的情况。如果题目中每个格子的代价不同则要改成Dijkstra用优先队列按dist排序并注意visited的剪枝条件要改为“如果dist比之前记录的更小才更新”。这个区别很关键笔试时如果没想清楚就用BFS去解带权图很容易在用例上超时。现场我卡了大概四十分钟在这道题上最后还是有一个测试用例没过。后来复盘想明白了是我的队列状态里dist字段在多条路径同时到达同一状态时出现了重复入队虽然答案正确但增加了常数开销导致差点TLE。如果直接用“以dist优先级的优先队列”替代普通队列效率会更高代码也只多两行。建议平时练习时多写优先队列版本兼顾正确性和性能。3.4 ACM模式下Java输入输出注意点京东笔试平台是牛客网编程题是ACM模式输入输出必须自己写这和力扣的核心代码模式完全不同。很多在学校只刷过力扣的同学上来就会在读取输入这里浪费大量时间。我这次的3道题输入模式分别是第一题一行字符串第二题第一行是区间数量n后面n行每行两个整数第三题第一行三个整数m、n、k然后m行每行n个整数。看起来简单但如果你不清楚Scanner的nextLine和nextInt的边界很容易出现读空行或者读串行的问题。我实际使用中比较稳的写法是全部用BufferedReader读取再用split切分而不是用Scanner。比如读整数矩阵BufferedReader br new BufferedReader(new InputStreamReader(System.in)); String[] first br.readLine().split( ); int m Integer.parseInt(first[0]); int n Integer.parseInt(first[1]); int k Integer.parseInt(first[2]); int[][] grid new int[m][n]; for (int i 0; i m; i) { String[] row br.readLine().split( ); for (int j 0; j n; j) { grid[i][j] Integer.parseInt(row[j]); } }Scanner在数据量大时性能较差实测读取几十万行的矩阵数据时Scanner可能比BufferedReader慢一倍以上在大数据量编程题中会直接导致读入超时。另外输出时建议统一使用StringBuilder拼接后再一次性输出而不是反复System.out.println后者也会造成不必要的性能开销。4. 常见问题与排查技巧实录4.1 时间分配策略选择题和编程题的合理顺序京东这场笔试总共两个半小时我的时间分配策略是先花8到10分钟快速浏览三道编程题判断难易然后用45分钟解答选择题之后按编程题从易到难的顺序逐题攻克。这个顺序不是我临时想的而是根据过去多家大厂笔试经验总结出来的。原因有三点第一选择题虽然单题分值低于编程题但胜在量大而且很多题只要临场思考一下就能确定答案属于“高确定性”得分点。安排在前面做可以稳定节奏建立信心。第二如果先做编程题很容易陷入“我怎么还没AC”的焦虑中等回头再做选择题心态已经波动反而连送分题都容易错。第三编程题的3道之间难度通常递增如果先把最容易的第一题AC保底后面即使时间不够也不会出现“交了白卷”的场面。4.2 数组越界和边界条件翻车现场笔试现场最容易翻车的不是算法想不出来而是代码跑出来越界。第二题区间扫描线如果输入里的某个区间是 [0, 10^9]而你的数组直接开了 10^9 大小的boolean数组那必然内存溢出正确做法是散列化或者排序事件法根本不用关心具体坐标范围。第三题BFS如果忘记记录visited在极端情况下队列会指数级膨胀直接把内存打爆。这里给大家一个自查清单写完代码先不要急着提交自己在脑子里过一遍边界条件——数组长度为0时返回什么只有一个元素时能处理吗两个端点相等时逻辑是什么输入中包含负数和超大数会不会出问题每次笔试我都至少捕获到两个由边界条件引发的低级错误节省了大量“编译失败”的提交次数。4.3 牛客网平台的隐藏规则牛客笔试平台的几个隐藏规则不说真的会吃亏。第一个是选择题的鼠标移出事件监听切屏会被记录并警告严重时直接交卷。这个规则各平台大同小异但牛客会明确在右上角显示切屏次数哪怕你只是不小心点到别的窗口也会被记录。所以考试前务必关闭所有无关弹窗和聊天工具最好使用独立的浏览器窗口全屏答题。第二个是编程题的评测有“多语言时间限制差异”。同样的题目Java的限时通常是C的2倍Python是C的3倍左右。但因为Java本身启动慢、运行解释执行像第三题这种O(n^3)复杂度的代码实际运行时间可能非常紧张。建议在提交之前对代码做“复杂度可行性初步评估”估算计算量在10^7以内是比较稳的超过10^8就要考虑换更高效的算法。第三个是关于“部分通过”的提交策略。你每提交一次错误答案系统都会记录提交次数。如果你一上来就写了个错误版本可能因为你试错次数多即使最后AC了面试官看后台记录也会觉得你思路不稳。我的策略是先在本地IDE上自测自己构造的样例通过后再提交尽量做到一次提交就有分没有额外把握不动手试错。4.4 我踩过的一个典型坑输出格式不对笔试时第一题我自测样例都通过了提交后却提示“通过0/10”后来发现是输出字符串首尾多了一个换行符。有人可能会觉得“多一个换行有什么关系肉眼看不都是一样吗”但判题系统是逐字节比对输出的多一个空行或者少一个空行都会直接判错。牛客对格式要求非常严格每行输出结束后可以有换行符但绝对不能输出多余的非必要空格或空行。比如第二题要求输出一个整数如果你输出的是“答案: 3”判题机直接判错。所以最后一个步骤永远是检查输出是不是完全符合题目描述——是输出一行一个整数还是每行一个整数是保留小数还是取整是否要去掉末尾的空格。这些小问题看似不起眼但在笔试实战中我见过太多人因为输出格式少AC一道题。4.5 考前两周的备战清单如果你现在离笔试还有两周时间我会给你一个非常落地的准备路径。第一重新梳理一遍Java集合类的底层实现和常用API尤其是Deque、PriorityQueue、HashMap的底层原理和扩容机制笔试时不一定直考但编码时离不开。第二把LeetCode热门100题里面的字符串、数组、贪心、DP、BFS这五类题刷透至少保证每类能独立写出两种以上解法。第三专门找牛客网的“ACM模式练习题”来练输入输出很多第一次参加笔试的人就死在Scanner读取大数据的性能上。我在考前专门做了一件事把最近两年京东、美团、字节的春招笔试题都找出来不看答案先限时两小时独立完成一遍然后对照题解查漏补缺。这个过程价值极大因为大厂的出题风格和命题热点是逐年趋同的你练过近年的真题就会对命题人的“口味”有一个直观感受。5. 对后续面试的启发与心态调整笔试结束后我花了点时间把三道编程题重新各写了一遍尤其是第三题用优先队列重新实现了Dijkstra版本同时整理了一份错题笔记。这个动作对我的后续面试帮助很大。因为春招面试里面试官经常拿着你笔试时没做出来的第三题来问思路如果你当场还是不会印象分就会很低但如果你能给出一种比笔试现场更优的解法反而会加分。心态上我想说的是大厂笔试不可能每道题都AC你不需要满分也不需要每道题都做出来。关键是稳定拿到所有送分题再在中等题上多得分难题争取部分通过这个总分就已经具备竞争力了。我这次笔试第一题全对第二题全对第三题只过了一半测试点最终顺利进入下一轮。你不需要做那个最亮眼的满分为王但这套策略能让你稳稳越过及格线。
返回列表