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

资讯详情

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

网易2018校招编程真题解析:从字符串到动态规划的刷题路线

网易2018校招编程真题解析:从字符串到动态规划的刷题路线 网易2018校招内推编程题集合我到现在还留着当年的题单。每次有学弟学妹来问校招笔试怎么准备我都会先让他们把这套题完整做一遍。这套题确实有代表性题量不大但覆盖了字符串处理、贪心、搜索、动态规划、数学推导这些校招笔试最高频的考点难度曲线也很有讲究前面送分、中间爬坡、最后压轴。不管你是想投网易还是想投其他互联网公司用这套题做自测都非常合适。这篇文章我会按参赛视角重新拆解这套题把每道题的思考过程、常见坑和考场策略讲透最后再给你一条可执行的刷题路线。1. 整卷复盘网易2018内推笔试的选题逻辑与难度分布1.1 内推批的流程与笔试定位网易2018校招的内推批时间点大概在8月底到9月初。和内推码、内推链接那一套流程一样简历筛选通过后进入统一在线笔试环节。和正式批相比内推批的笔试有一个特点它更像一个“资格筛选器”而不是“排名赛”。题目不会出得特别偏门而是集中考察你基础算法功底的扎实程度尤其看重编码速度和边界处理能力。为什么我强调这一点因为很多人在准备校招时总喜欢去死磕冷门数据结构和高级算法结果到了笔试现场发现八道题里没有一道考AC自动机也没有考后缀数组全是“数据结构基本功经典算法模型”的组合题。网易这套题最大的价值也在这里它帮你划了一条线告诉你“大厂笔试真正要的是什么”。如果你能把这套题的每一道都吃透应付大多数主流互联网公司的校招笔试基本够用了。1.2 八道题的知识点版图当年的题单网上还能找到普遍流传的版本是8道编程题限时120分钟。题型大致分布如下我按考点类别整理了一下考点类别出现频次难度评级常见出题角度字符串处理/模拟高简单到中等去重、翻转、格式化输出、统计片段贪心/规律推导中高中等构造操作序列、最优策略、反推路径DFS/BFS搜索中高中等偏难组合枚举、最短步数、剪枝优化动态规划高较难状态设计、转移方程、正负值处理数学/枚举中中等找规律、二进制视角、组合计数网易为什么偏爱这些考点原因不难理解。网易当时的业务盘子很大互联网产品、游戏、音乐、教育都有覆盖这些业务对工程师最基础的要求就是两类能力第一能把业务逻辑用代码快速实现出来这对应字符串和模拟题第二能在复杂约束下设计出高效的算法这对应搜索、DP和数学推导。尤其是游戏部门搜索和数学规律题几乎是标配因为游戏里的路径寻路、数值平衡、技能效果计算本质上都是这些算法的业务翻版。2. 那些年我们一起做过的经典题逐题拆解思路2.1 字符串碎片考察基础功的签到题这套题里有一道很经典的签到题题面大致是给一个字符串把它看成由连续相同字符组成的若干碎片拼接而成比如 aaabbaaac 由 aaa、bb、aaa、c 四个碎片组成计算所有碎片的平均长度结果保留两位小数。这道题放在第一题的位置作用很明确让你热身也让你别在第一题就翻车。解题思路非常简单从头到尾扫一遍统计字符变化次数。每次相邻字符不同就说明开了一个新碎片相同则当前碎片长度加一。碎片总数等于变化次数加一。double avgFragmentLength(string s) { int cnt 1; // 碎片个数至少为1 int total s.size(); // 总长度就是字符串长度 for (int i 1; i s.size(); i) { if (s[i] ! s[i - 1]) cnt; } return (double)total / cnt; }这题看似无脑但有一个很容易丢分的地方输出格式。题目要求保留两位小数很多人用 cout 直接输出结果被系统判错。正确姿势是 printf(%.2f, ans)或者用 cout fixed setprecision(2)。另外int 除以 int 在 C/C 里是整除必须先把其中一个转成 double这个细节对刚上考场、有点紧张的人来说非常容易翻车。2.2 魔法币从操作反推路径的典型题这是当年那套题里被讨论最多的一道题面大概是初始有0个魔法币你有两台魔法机器机器1对当前数量x操作后得到2x1个机器2得到2x2个现在要通过一系列操作恰好得到n个魔法币输出操作序列。这道题的正解非常反直觉。你可能会自然地想从0开始正向模拟每一步有两个分支枚举所有可能路径直到出现n。但n的数据范围很大正向枚举是指数复杂度必挂。正确思路是从n倒着推。关键观察是奇偶性2x1永远是奇数2x2永远是偶数。所以如果当前数量是奇数最后一步一定来自机器1如果是偶数最后一步一定来自机器2。一直倒推到0再把步骤反转输出就行。def magic_coin(n): ops [] while n 0: if n % 2 1: n (n - 1) // 2 ops.append(1) else: n (n - 2) // 2 ops.append(2) return .join(reversed(ops))这道题还有一个更漂亮的解释把操作看成二进制末尾追加数字。机器1对应在二进制末尾追加1机器2对应追加0。所以你要得到n其实就是把n不断右移每次看最低位是1还是0就知道最后一步用了哪台机器。用二进制视角理解这道题之后你会对很多“逆推构造”类题目有全新的感觉。这种从结果反推过程的思维在笔试里出现频率非常高值得专门训练。2.3 幸运的袋子DFS加剪枝的进阶题这道题比前面两道上了一个台阶。题面大意是一个袋子里有n个球每个球上有一个编号。从袋子中取出若干个球如果这些球上的数字之和大于它们的乘积则称为一个“幸运的袋子”。问共有多少种不同的取法。我第一次做这道题的时候没做任何优化就直接枚举所有子集结果超时超到怀疑人生。这题的考点非常明确DFS枚举组合 排序剪枝 去重。核心思路是先对数组从小到大排序然后DFS枚举组合。在递归过程中维护当前的和sum和乘积product。遇到一个新球时先判断加入后是否满足sum x product * x如果满足就继续递归一旦不满足由于数组已经升序后面更大的数也一定不满足可以直接跳出循环这就是剪枝的关键。还有一个容易忽略的坑数字1。加上1会让和增加1但乘积不变所以即使当前和小于等于乘积加一个1也可能让不等式方向改变。因此遇到1要特殊处理不能直接剪枝。int ans 0; void dfs(vectorint a, int idx, int sum, long long prod) { if (idx a.size()) return; for (int i idx; i a.size(); i) { if (i idx a[i] a[i - 1]) continue; // 去重 sum a[i]; prod * a[i]; if (sum prod) { ans; dfs(a, i 1, sum, prod); } sum - a[i]; prod / a[i]; } }这道题我建议所有准备校招的人都要精做。它几乎覆盖了搜索题的所有要素怎么设计DFS参数、怎么用排序创造条件剪枝、怎么处理重复元素的计数问题。你把这题吃透了再去写其他组合枚举类题目会顺手非常多。2.4 合唱团动态规划的压轴题合唱团这道题可以说是当年那套题里区分度最高的一道。题面大意有n个学生排成一排每个学生有一个能力值。要从中选出k个学生使得任意两个相邻选出的学生在原队列中的位置编号差不超过d并且这k个学生的能力值乘积最大输出这个最大乘积。这题我当年在考场上想了很久后来复盘发现它考察的其实是动态规划里一个非常经典的模型在“位置已选数量”双维度上做状态转移。状态设计是核心。定义dp_max[i][j]表示以第i个位置的学生作为最后一位被选中的学生已经选了j个学生时乘积的最大值dp_min[i][j]表示对应的最小值。为什么还要维护最小值因为能力值存在负数。如果当前要乘的能力值是负数那么之前的最小乘积反而可能变成之后的最大乘积。这种“最大值最小值同维护”的技巧在涉及正负号的乘积DP里是标配。转移方程的思路是这样的既然第i个位置是最后一位那前一位选中的位置p必须在i-d到i-1之间。枚举所有可能的p用dp_max[p][j-1]和dp_min[p][j-1]分别乘以a[i]取最大值和最小值更新当前状态。// 初始化 for (int i 1; i n; i) { dp_max[i][1] a[i]; dp_min[i][1] a[i]; } // 转移 for (int j 2; j k; j) { for (int i j; i n; i) { for (int p max(1, i - d); p i - 1; p) { dp_max[i][j] max(dp_max[i][j], max(dp_max[p][j-1] * a[i], dp_min[p][j-1] * a[i])); dp_min[i][j] min(dp_min[i][j], min(dp_max[p][j-1] * a[i], dp_min[p][j-1] * a[i])); } } }很多同学一看到DP就害怕其实这类题你只要抓住两个问题第一状态里要保存哪些信息第二最后一个状态是怎么从前一个状态转移来的想通这两点剩下的就是代码实现。这道题还提醒你一件事笔试里凡是“选若干个、带约束、求最大/最小”的题十有八九是动态规划不要用贪心硬解。2.5 跳石板BFS还是DP怎么选跳石板这道题也很有代表性。题面大意从编号N的石板跳到编号M的石板每次从当前石板x出发只能跳x的某个约数对应的步长不只包含1和它本身问跳到M最少需要跳几次如果跳不到输出-1。这种“最少步数”的描述很多人第一反应就是BFS。BFS确实能解第一次扩展到目标节点时就是最少步数这个结论是广度优先搜索的基本性质。但这题有个问题M的数据规模可能到10万甚至更大对每个节点都做一次O(sqrt(x))的约数分解代价不小而且图里的边数非常多BFS会消耗大量内存和时间。我当时更推荐的做法是DP。设dp[i]为从N跳到i的最少次数初始化为一个很大的数dp[N]0。从N开始向后遍历对于当前位置i如果dp[i]不是初始值说明它可以到达然后枚举i的所有约数去掉1和它自身对每个可行步长p更新dp[ip] min(dp[ip], dp[i] 1)。这题为什么可以用DP而不是必须用BFS因为每次跳跃都是递增的从N到M的方向是单向的。虽然状态之间不是严格的DAG但从左往右扫描不会出现回跳所以DP完全可以覆盖而且空间上省掉了队列时间上只要预处理优化约数枚举整体更稳。跳石板这道题给我的启发是算法选型不要只看“题型标签”更要看状态转移的顺序。最短步数当然优先想BFS但如果状态是单调递增的DP往往更轻量。这种选择和取舍能力才是笔试真正想考察的东西。3. 针对网易风格笔试的刷题路线从入门到笔试及格3.1 先搞定输入输出和代码模板很多人觉得输入输出很简单不值得练习但校招笔试里第一挂点就是它。网易这套题当年用的是在线OJ系统输入输出格式要求非常严格多一个空格、少一个换行都会直接WA。你需要把常用语言的模板练到闭着眼睛都能写出来。我用C的时候第一行一定是关闭同步#include bits/stdc.h using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); // ... return 0; }如果你用Java那就用BufferedReader和StringBuilder千万不要在循环里大量使用System.out.println否则大数据量下极其容易超时。如果你用Python一定要熟悉sys.stdin.read()一次性读取所有输入再按行切分解析。笔试题还有一个高频设定多组输入读到EOF结束。写法是这样的int n; while (cin n) { // 处理一组数据 }这个模板看起来不起眼但如果你笔试前一天没默写过考场上一边紧张一边敲很容易忘。我建议你把这套东西整理成自己的“开卷小抄”考前反复练确保十分钟内能完整敲出一个能跑通的框架。3.2 按高频考点分配刷题优先级刷题最忌讳没有侧重点东一榔头西一棒子。我当时给自己定了一个优先级表现在回头看对网易这一套题依然适用。优先级考点推荐训练量达标标准第一梯队模拟、字符串、排序每天3-5道一遍过不调试第二梯队贪心、DFS/BFS每天2-3道30分钟内想出思路第三梯队动态规划、数学规律每天1-2道吃透经典题不贪多第一梯队是保底分必须拿稳。这类题考察的纯粹是代码实现能力练得多了考试时就是肌肉记忆。第二梯队是拉开差距的关键网易这套题里的幸运的袋子、跳石板都属于这个级别。第三梯队的DP题短时间内很难速成但只要把合唱团这类经典题反复做熟起码能拿过程分。还有一个建议刷题时多关注“这个题考什么”而不是“我能不能AC”。一道题做不出来看题解后要能说出来它考的是哪个模型、用了什么剪枝、当时卡在哪一步。这种结构化梳理比盲目刷两百道题更有效。3.3 限时模拟与错题复盘的正确姿势刷题和真正的笔试之间有一个巨大的差距时间压力。很多人平时刷题能从容思考一到限时环境就手脚发凉。所以我特别建议你在正式笔试前至少做3次完整的限时模拟。模拟时要注意几点第一严格按照120分钟8道题来中途不暂停、不查资料第二每道题用记事本记下开始时间和卡住的时间点方便复盘时定位问题第三不要因为某道题卡住了就提前结束坚持到时间结束训练耐受力。复盘比做题更重要。每次模拟完我建议你做一个错误分类是逻辑错了还是边界没想清楚还是时间复杂度估计错误还是输入输出格式问题。分类之后你会发现自己有一个固定的弱点。有人每次都在DFS的参数设计上出错有人总是在数组越界上栽跟头。找到这个规律之后专项练习的效率会非常高。4. 笔试现场最容易踩的坑附带排查清单4.1 输入输出格式坑WA重灾区在线笔试和本地IDE有一个很大的不同本地跑得欢提交就报错。最典型的坑就是输入输出格式。第一个坑是多组输入。题目说了“输入包含多组测试数据以EOF结束”但你没有写while循环只处理了一组数据结果样例能过提交零分。第二个坑是输出格式。题目要求每个结果占一行你多打了一个空格或者漏了末尾换行都会WA。第三个坑是C的浮点数输出精度题目要求保留两位小数直接用cout默认输出可能只有六位有效数字要用fixed和setprecision。我的建议是一看到输入输出格式描述就立刻在草稿纸上画一个“输入样例→输出样例”的对照图明确每一行输出是什么、中间有没有空格、末尾要不要换行。这个习惯能帮你避开至少30%的WA。4.2 超时排查别让垃圾代码拖垮你在线笔试系统对运行时间的限制通常很紧尤其是数据规模比较大的题目超时几乎和WA一样常见。超时的原因各有不同。有人是用了cin却不关同步默认的iostream和stdio同步机制会拖慢大量读入有人是在循环里频繁调用耗时函数比如Java的System.out.println还有人是最根本的算法复杂度问题——数据范围10^5你写了个O(n^2)的暴力枚举不超时才怪。排查超时有一个固定套路先看数据范围估算你的算法复杂度是否在可接受范围内。一般10^6的规模O(n)没问题O(n log n)勉强可以O(n^2)基本必挂。如果复杂度没问题再看代码层面有没有过度使用STL、频繁创建对象等问题。实测下来绝大多数超时都是复杂度问题不是常数问题。4.3 样例过了却WA的边界问题有一种最让人崩溃的情况样例输出完全一致提交却是WA。这种时候十有八九是边界问题。我整理了一份自测边界清单每次提交前对照检查一遍错误类型典型场景应对方式整数溢出能力值乘积、累加结果超过int范围直接用long long别犹豫空输入/空串字符串处理题输入为空提前判空避免越界单元素n1时循环边界、判断逻辑单独跑一遍最小规模数据全相同元素排序后相邻去重逻辑出错构造全1或全相同字符串测试负数处理乘积DP、排序后第一个数是负数关注正负号对结果的影响尤其是合唱团那类乘积题能力值存在负数时如果你只维护了最大值最后结果很可能错。很多WA不是算法思路错而是数据类型没开够或者特殊情况没处理。所以写完代码之后别急着提交先跑一遍最小规模、最大规模、全是相同元素这几组数据心里更有谱。4.4 考场时间分配与心态最后聊一个很多人忽略的环节考场上怎么分配时间。我的习惯是拿到题目先花两分钟把八道题全部扫一遍快速标记出送分题、中等题和压轴题。然后按照“保底分优先”的原则做题先把送分题和简单模拟题全部AC再回头啃中等题最后剩多少时间给压轴题就随缘。单题限时也很重要。我的经验是一道题如果35分钟还没有任何思路立刻跳过不要恋战。笔试是一场筛选不是一场竞赛你不需要拿满分。把你能拿的分全部拿稳通过率已经很高。最可惜的是那种在最后一道DP题上耗了40分钟结果前面简单题没时间检查白白丢分的情况。心态上你要告诉自己这套题做不到全对完全正常。网易2018内推批的题目本来就是用来区分学生的压轴题就是让少数人拿到的。你能把送分题全部拿满中等题做出大部分就已经超过绝大多数考生了。最后再分享一个我自己的体会后来我带学弟学妹准备校招发现一个规律能把魔法币这种反推题讲清楚的人算法基础都不会差能把合唱团的DP状态设计说明白的人笔试基本都能过。这套2018年的题单我推荐过很多人认真做完并做了复盘的人后来笔试结果都不错。如果你最近也在准备校招不妨给自己一个周末把这套题老老实实做一遍。做完之后你可能会回来感谢我。
返回列表