网易2019实习笔试编程题解析:二分、前缀和与边界条件避坑指南

网易2019实习笔试编程题解析:二分、前缀和与边界条件避坑指南 这套2019年的网易实习生招聘编程题放到今天回头看依然是我心目中大厂笔试的“教科书级样本”。它不考偏题怪题题型集中在模拟、贪心、二分、前缀和这几类最基础的算法上但每一道题都有坑稍不注意就会翻车。当年我刷这套题的时候有个很深的感受网易出题不追求“难倒你”而是追求“看你会不会用最合适的数据结构和边界思维去解决一个实际问题”。这篇文章就把这套题里我印象最深的几道题拆开揉碎讲一遍再聊聊笔试现场的时间分配和踩坑经验给正在准备大厂实习笔试的同学一个可以直接参考的复习方向。先说适合谁看如果你正在准备2025年或2026年的暑期实习、校招提前批目标是大厂后端、算法或测试开发岗这套题非常适合作为笔试前的练手材料。难度大致在LeetCode Medium偏下的水平但比单纯刷题更考验临场读题和代码实现的稳定性。我会从题型风格讲起逐题给思路、给代码、给注意事项最后整理一份笔试现场的实战清单。1. 网易2019实习笔试到底考什么1.1 一张表看懂题型分布我根据网上流传的版本和自己的记忆把2019年网易实习生招聘编程题集合整理成下面这个表格。每年题号可能有调整但题型基本是稳的题号题目俗称核心考点难度1牛牛的闹钟时间转换 二分查找简单2俄罗斯方块计数 取最小值简单3丰收前缀和 二分查找简单偏中等4表达式求值穷举所有括号与运算符组合简单5整理房间几何 全排列暴力困难从表格能看出来网易笔试的选题非常“基础”没有动态规划、没有图论、没有复杂字符串算法全是计算机专业大一到大三一定会接触的知识点。但基础不等于白给后文你会看到越是基础的题越容易在细节上翻车。1.2 出题风格为什么网易爱考模拟和贪心很多同学刷题喜欢刷难题觉得笔试会出DP、出树、出图。但网易这套题几乎全是“模拟题”和“思维题”。我后来复盘时总结了三点原因第一实习生岗位需要的是“能干活的人”。笔试不是奥林匹克竞赛面试官想确认的是给你一个业务场景你能不能快速建模、选对数据结构、写出没有边界错误的代码。模拟题正好能考察这个能力。第二这套题的时间限制很紧。我记得总共就那么点时间要读题、思考、编码、调试如果全是Hard级别的算法题区分度反而不好。用中等题考察代码实现的“稳”比用难题考察思维能力更有效。第三网易出题喜欢套一层“业务外衣”。什么闹钟、俄罗斯方块、果园收苹果本质都是经典算法但需要你先读懂题面、抽象出模型。这个抽象过程就是工作中的需求分析能力。所以备考网易我的建议是别死磕难题把LeetCode上简单和中等难度的数组、字符串、模拟题刷熟尤其要练“10分钟内写完一道简单题并且一次AC”的速度。2. 我印象最深的5道真题题解2.1 牛牛的闹钟二分与暴力都能过这道题的题面大概是这样牛牛早上需要X分钟到教室上课时间是A时B分他定了N个闹钟每个闹钟有小时和分钟。问在保证不迟到的前提下他最晚可以定在哪个闹钟时间。我第一次做的时候直接暴力遍历把所有闹钟时间转成“从0点开始的分钟数”然后和“最晚起床时间 上课时间 - X分钟”做比较取不大于它的最大值AC没问题。后来发现这道题用二分更优雅因为闹钟时间可能不是有序输入的但我们可以排序后二分。#include bits/stdc.h using namespace std; int main() { int n, x, a, b; cin n; vectorint t(n); for (int i 0; i n; i) { int h, m; cin h m; t[i] h * 60 m; } cin x a b; int limit a * 60 b - x; sort(t.begin(), t.end()); // 二分找最后一个 limit 的元素 int idx upper_bound(t.begin(), t.end(), limit) - t.begin() - 1; cout t[idx] / 60 t[idx] % 60 endl; return 0; }这题的坑有两个。一是时间转换要统一单位别直接对“小时”和“分钟”分开比较很容易忘记借位二是“上课时间减去路上时间”可能是负数比如上课时间在凌晨闹钟都在前一天深夜这时候limit是负数二分要处理好。网易写题面的时候可能不会明确说这些边界但数据里一定会测。2.2 俄罗斯方块一行代码核心逻辑的“陷阱题”这道题也是一道经典题。题面是一个n列的游戏区域有m个方块依次落下每个方块只会落在某一列的最上方方块是1x1大小。当某一行的所有n列都有方块时这一行消除上面的块整体下移。问最终消除了多少行。很多人一看到“消除行”“整体下移”就开始模拟整个二维数组写得很复杂。但实际上有一个关键观察既然每次消除是整行消除而且方块只在指定列累加那么最终能消除的行数等于所有列中“方块数量最少的那个列”的数量。int n, m; cin n m; vectorint col(n, 0); for (int i 0; i m; i) { int c; cin c; col[c - 1]; } int ans col[0]; for (int i 1; i n; i) ans min(ans, col[i]); cout ans endl;你没看错核心逻辑就这么多。这道题是典型的“听题觉得难想通觉得简单”。它考察的是从复杂规则中抽象本质的能力。我在牛客网上看到不少人评论区说“我模拟了半小时内存越界了还没写对”就是因为没有先花时间想清楚数学模型。这里给一个通用经验凡是遇到“消除”“合并”“移动”类规则先别急着模拟思考一下规则自身是否有数学表达。多数情况下规则可以化简为计数或累加问题复杂的模拟代码反而容易写错。2.3 丰收前缀和二分的标准模板“丰收”这道题的题面是牛牛有n堆苹果第i堆里有a[i]个苹果。有q次询问每次问第x个苹果是从第几堆开始数的。这里“第几堆开始数”的含义是苹果按堆的顺序从头数找到第一个累加和大于等于x的堆。这题我印象特别深因为它是“前缀和二分”最经典的入门题。先用一个数组pre[i]表示前i堆苹果总数然后每次询问用二分查找在pre数组中查找第一个不小于x的位置。cin n; vectorlong long pre(n 1, 0); for (int i 1; i n; i) { long long num; cin num; pre[i] pre[i - 1] num; } cin q; while (q--) { long long x; cin x; int idx lower_bound(pre.begin() 1, pre.end(), x) - pre.begin(); cout idx endl; }两个容易踩的坑我必须说一下。第一a[i]和x要用long long因为n最大可以到十万苹果数量累加后可能超过int范围。第二lower_bound查找的是“第一个不小于x的下标”因为pre数组里第i个元素恰好表示“前i堆的总数”所以二分的边界是pre.begin()1而不是pre.begin()。这里下标搞错结果就会整体偏移一位。这道题的本质是“在线查询区间累加定位”后面很多更难的题比如带修改的区间查询、树状数组、线段树其实都是在这个基础上扩展的。把这道题的思路吃透相当于给数据结构的复习开了一个好头。2.4 表达式求值只值5分钟的送分题题目给三个数a、b、c你可以在它们之间插入加号或乘号还可以加括号改变运算顺序问能得到的最大值是多少。这题因为只有三个数和两个运算符所以所有可能的括号形式一共就那么几种枚举就行。我记得有人会把这题想复杂试图去“动态规划求所有加括号方案”。没必要。三个数全部可能的结果只需要考虑以下几种(a b) c(a b) * c(a * b) c(a * b) * ca (b * c)a * (b c)甚至严格来说由于加法和乘法都满足结合律部分形式是重复的但程序员不差这点计算量全部算一遍取最大值最稳妥。int a, b, c; cin a b c; int ans 0; ans max(ans, a b c); ans max(ans, a b * c); ans max(ans, a * b c); ans max(ans, a * b * c); ans max(ans, (a b) * c); ans max(ans, a * (b c)); cout ans endl;这道题的价值在于提醒我们笔试中遇到看起来像是“难题”的题先评估数据规模。当数据规模小到可以穷举时直接穷举往往是性价比最高的解法。很多同学一上来就想到DP反而把简单问题复杂化浪费时间还容易出错。2.5 整理房间最难的几何暴力题这套题里真正的压轴题是“整理房间”。题面大概是平面上有四个点每个点可以移动一步上下左右问最少移动多少步能让四个点构成一个正方形。四个点不一定按顺序给出而且可能有多个点重合。这题是典型的“题目短坑多”。难点在于正方形可能是斜的不一定是轴对齐的四个点的对应关系不确定需要枚举配对每个点移动步数等于曼哈顿距离。我当时是这么解的枚举四种配对方式固定第一个点然后枚举它和哪个点作为正方形的一条边剩下两个点自动确定再枚举正方形是“左上-右下”还是“右上-左下”两种方向对每种情况计算四个点分别移动到对应顶点的曼哈顿距离总和取最小值。// 核心思路枚举点对和方向计算最小曼哈顿距离和 // 伪代码 int ans INF; for (int i 0; i 4; i) { for (int j 0; j 4; j) { if (i j) continue; // 假设点i和点j构成正方形一条边计算另外两个顶点的位置 // 再让剩余两个点分别匹配这两个顶点取曼哈顿距离之和 // 更新ans } } cout ans endl;这题能拿部分分的技巧是先处理所有点坐标相同或只有两个不同坐标的简单情况把这些写对就能过一部分测试用例。完整解法需要比较强的几何直觉和代码组织能力如果你在笔试中遇到我建议先跳过把前面四题全部AC后再回头啃。这也是网易这套题的精妙之处它在考验你“取舍”和“时间分配”的能力。3. 笔试现场的时间分配与答题策略3.1 先做哪道题按分值和难度排序网易这套题一共5道我建议的作答顺序是表达式求值 - 牛牛的闹钟 - 俄罗斯方块 - 丰收 - 整理房间。理由很简单前四道都是可以在15分钟内拿下的题把这些AC了心态就稳了最后再做最难的那道能做多少算多少。很多同学喜欢按题号从前到后做结果第一道就卡住后面明明有简单题也没时间看这是最亏的。我后来面试复盘的时候养成了一个习惯拿到题先把所有题都扫一遍给每道题打个难度标记再决定做题顺序。这在实际工作中也很重要——先做高优先级、低成本高收益的事情而不是被排列顺序绑架。具体的时间分配上我给自己定的规矩是前四道题每道控制在15分钟以内超过20分钟还AC不了就果断做下一道。整套题留下来至少30分钟给“整理房间”或回头调试。笔试的通过标准往往不是全对而是尽量拿分把时间花在能确定拿到的分数上才是最优策略。3.2 输入输出那些坑在线笔试和本地IDE不一样网易的笔试一般是在牛客网进行在线OJ的输入输出和本地IDE有微妙差别。最大的坑是你需要处理多组输入或循环读入直到EOF的情况而不是像平时写算法题那样只读一次。我当年就栽过跟头。本地IDE里我写cin n;然后处理一组数据一测没问题但提交后只能过部分用例。后来才意识到某些题的数据是多组用例或者是先给一个T表示测试组数需要在外层套循环。更隐蔽的是有些题输入数据最后有多余空格或换行用cin 通常没问题但如果你用getline读字符串就要小心换行符残留。还有一点在线OJ对输出格式非常严格。输出结果老老实实按题目要求来不要画蛇添足输出调试信息。我见过有人提交时代码里忘了删cout debug: 直接导致wrong answer这种错误非常可惜。3.3 暴力先拿部分分再优化网易这套题的数据范围我记得不算特别大部分题暴力解法也能拿不少分。比如“丰收”这道题如果你不会二分直接每次询问从头累加遇到数据弱的测试点也能过一部分。但后面会有几组大数据暴力就会超时。正确的策略是先确保暴力解法能跑通样例把这个作为兜底方案然后如果时间充裕再优化成二分或前缀和。这个思路在“整理房间”那道题上尤其关键——完整几何解法一时半会儿写不出来那就先把所有坐标相同的简单case处理掉至少拿到基础分。我后来在大厂笔试题里见过不少“部分分机制”不同测试点数据范围不同小数据暴力能过大数据需要优化。所以一定不要因为写不出最优解就放弃暴力解提交上去往往能拿30%到70%的分这对通过笔试线非常重要。4. 常见问题与实战避坑记录4.1 数据范围没看清导致数组开小这套题里“丰收”一题就有n100000的量级前缀和数组要开n1而且累加和要long long。我刚开始刷的时候用int存pre数组结果第十组数据就开始溢出输出完全乱掉排查了很久才意识到是数据范围的问题。这类问题在真实笔试里太常见了。很多题不会在题面里直接告诉你“请用long long”但数据范围一算就知道超过int了。我的习惯是看到题目中涉及累加、累乘、计数先把所有相关变量都设为long long宁多勿漏。笔试不像工程项目不会因为用了long long就性能不足但会因为溢出错得莫名其妙。4.2 二分写死循环的排查做“丰收”和“牛牛的闹钟”这类二分题时很多人会遇到死循环或答案差1的问题。我记得有人在网上贴过自己写的二分查了半天没发现问题其实往往出在while循环的边界条件和mid的取整方向上。我自己有一个特别稳的模板从此再没写错过// 返回第一个 target 的下标 int low 1, high n; while (low high) { int mid (low high) / 2; if (pre[mid] target) high mid; else low mid 1; } // 返回最后一个 target 的下标 int low 0, high n; while (low high) { int mid (low high 1) / 2; if (pre[mid] target) low mid; else high mid - 1; }注意第二个模板的mid要加1再除以2否则当low和high相邻时会陷入死循环。这个细节几乎每一届都会有人栽。如果你用的是STL的lower_bound和upper_bound要记住它们返回的是迭代器算下标时一定要减begin()而且要搞清楚“第一个大于等于”和“第一个大于”的区别。4.3 边界条件速查表我把这套题常见的边界条件整理成一个清单笔试前扫一眼能避免大量低级错误题目关键边界常见错误牛牛的闹钟上课时间减去路程后可能是负数闹钟时间相同时取哪个忘记借位二分边界偏移俄罗斯方块n1时答案就是这一列的方块数所有列数量相等时答案正确数组下标从0开始导致少统计一列丰收苹果总数用long longx恰好等于前缀和某一位时取哪个堆lower_bound和upper_bound混淆下标偏移表达式求值三个数可能有0结果可能超过int没有考虑加括号的乘法形式整理房间多个点坐标相同正方形可能斜着配对枚举不全曼哈顿距离计算错误这个速查表不是凭空想的是我自己反复刷题后总结的。笔试时如果某道题的测试用例过不了先对照这张表排查往往一两分钟就能定位问题。4.4 心态和节奏挂了不等于能力问题最后说点实在的。网易2019这套题放到现在依然是很好的练习材料但我想给大家打个预防针笔试挂掉的原因太多了不一定是你算法不行也可能是输入输出格式、环境配置、网络卡顿、当天状态差。我一个同学当年笔试这套题因为牛客网的编辑器自动缩进和他本地IDE不一样某道题少了个右括号找了好几分钟才编译通过最后差一道题没过线。后来他秋招照样拿了别家的大厂offer所以一次笔试的结果什么也代表不了。如果你正在准备笔试我的建议是把网易这套题当作“体检”看看自己在模拟、二分、边界处理这些基础能力上有没有短板。每道题做完后别急着看题解先自己复盘——是卡在思路、代码实现还是边界条件然后针对性地补。刷题刷的不是数量是“把会做的题做对”的稳定性和“把不会做的题拿到部分分”的取舍能力。说实话网易这套题的代码量都不大核心代码往往不超过30行。它真正考验的是你在有限时间内读题、建模、编码、自测的完整闭环。把这个闭环练顺了比多做一百道难题都管用。这篇文里的代码模板和避坑清单是我自己一次次翻车后攒下来的希望能帮你少走点弯路。