ARTICLE DETAIL

资讯详情

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

网易2018校招编程真题全解析:从魔法币到游历魔法王国

网易2018校招编程真题全解析:从魔法币到游历魔法王国 如果你准备过大厂的笔试对《网易2018校园招聘编程题真题集合》这个名字应该不陌生。我前几天整理电脑里的旧文件又把这份题集翻了出来完整刷了一遍。说实话这套题放在现在依然有很强的参考价值它把互联网公司校招笔试里最常碰到的几类问题浓缩在七八道题目里难度梯度也拉得很开既有一看就会的送分题也有需要绕几个弯才能想清楚的综合题。对于正在准备暑期实习、秋招提前批或者单纯想补算法基础的人来说这套题都是一份非常合适的练手材料。下面我会按真题集里的典型题目来拆解先说清楚这套题到底在考什么再挑几道最有代表性的题完整复盘解题过程最后聊一聊刷题时容易踩的坑以及怎么把一套老题的价值最大化。题目名称和题面我按当年牛客网上的回忆版整理细节可能有个别出入但考点和解题思路是可靠的。1. 这套真题集到底在考什么先看试卷结构再谈刷题价值1.1 试卷结构七八道题两个小时的脑力冲刺网易2018校招的线上笔试一般安排两个小时左右编程题大概四到八道。这套真题集合里我印象比较深的有魔法币、相反数、字符串碎片、重排数列、操作序列、小易喜欢的数列、游历魔法王国等。题目数量不算多但每一道都卡在一个常见考点上几乎没有凑数题。我当时第一次做这套题的时候感觉最明显的是时间节奏前两道送分题大概各需要五分钟中间两道中档题需要十五到二十分钟后面两道难题可能要卡上半小时。如果你在送分题上磨太久后面综合题基本没有思考空间。所以这套题其实也在训练一个很重要的能力——快速识别题目类型然后决定投入多少时间。下面这张表是我根据回忆整理的题目与考点对应关系方便你建立整体印象。题目回忆版核心考点一句话难点魔法币数学构造 / 倒推正向模拟状态爆炸倒推每次减半相反数字符串处理反转后前导零要正确处理字符串碎片字符串计数连续相同字符块数统计别想复杂重排数列数论 / 构造4的倍数、2的倍数与其他数的数量关系操作序列双端队列思想找规律后只需按奇偶输出小易喜欢的数列动态规划直接枚举转移太慢需要容斥优化游历魔法王国树 / 贪心最优路径与多出来的步数折算1.2 从考点分布看网易的用人筛选逻辑这套题里的“送分题”并不只是让你热身的它们承担了筛选功能。比如相反数和字符串碎片如果你在十分钟内不能AC说明字符串处理的基本功还不扎实。对于工程类岗位来说字符串处理是日常开发里最绕不开的东西笔试考它并不是为了刁难人而是想快速筛掉基本功薄弱的人。中档题比如重排数列和操作序列考的是把数学规律和数据结构状态理清楚的能力。这类题通常不要求你掌握冷门算法但需要你在有限时间内观察出规律并且用代码准确地表达出来。很多同学能想出思路但边界条件写错最终只能过部分用例这恰恰是笔试最有区分度的地方。高难题比如小易喜欢的数列和游历魔法王国则用来区分哪些人能从“会写代码”进阶到“会分析复杂度、会设计状态”。网易这种大厂筛选的不只是会背题的人而是能在限定时间内快速抽象问题模型、找到正确算法的人。这也是为什么即使过了这么多年这套题依然有参考价值大厂笔试的筛选逻辑没有变。1.3 为什么一份2018年的题库现在还能用算法题和业务代码不一样它没有版本迭代。树的遍历、动态规划、贪心这些核心思想不会过期你现在去牛客刷题看到的题目考点仍然大量落在这几个范围里。你可能会说现在面试更卷了很多公司开始考困难题但正因为如此基础题的参考价值更大了如果连2018年这套题里的中档题都写不利索直接去啃LeetCode困难题大概率是空中楼阁。更关键的是这套题里的很多题目思路在后续笔试里反复出现。比如“魔法币”这种通过最终状态反推操作序列的题我后来在其他几家公司的笔试题里都见过变体。把老题真正吃透比盲目刷新题有用得多。2. 四道必刷题的题面复盘把“回忆版”题目讲清楚2.1 魔法币一个看起来很绕的数学构造题题目大意小易一开始有0枚魔法币他面前有两种魔法机器。第一种机器投入x枚魔法币可以产出2x1枚第二种机器投入x枚魔法币可以产出2x2枚。小易每次操作会把当前所有的魔法币全部投入其中一台机器现在他想正好得到n枚魔法币请你输出机器操作序列。举个例子如果n等于10可能的输出是类似“122”这样的字符串每一位表示选择第1台还是第2台机器。这道题表面上是个模拟题但如果你从0开始正向搜索每次有两种选择状态会呈指数增长。第一次做的时候我甚至想过用BFS后来发现n稍微大一点就爆了。正确做法是反过来思考这也是这道题最有价值的地方从目标n倒推根据奇偶性判断最后一步用了哪台机器因为第一种机器永远产生奇数枚第二种机器永远产生偶数枚。2.2 相反数字符串题里的“送分题”考察点题目大意输入一个整数n把它的十进制表示数字顺序颠倒去掉前导零后得到一个新的整数rev然后输出nrev。比如输入1325反转得到5231相加得到6556。这道题本身不难但很能考察基础功。有些人会尝试用取模和除法一位一位拆也能做出来但代码容易写长而且容易在处理0的时候出错。更直接的方式是把整数转成字符串反转字符串再转回整数。为什么这道题值得复盘因为它的核心不是“会不会反转字符串”而是能不能想清楚前导零的语义。反转后如果开头是0比如输入1200反转得到“0021”转成整数后应该是21而不是0021。这类细节在笔试里很容易被忽略一旦忽略就会出现只过部分用例的情况。2.3 字符串碎片输出格式比算法更坑的题题目大意一个由小写字母组成的字符串可以看成若干由相同字母连续组成的“最大碎片”。例如“aaabbaaac”可以被切分成“aaa”“bb”“aaa”“c”四块。现在输入一个字符串要求输出所有碎片的平均长度保留两位小数。这道题最核心的洞察是不需要真的去切割字符串只需要数一数有多少个“连续相同字符段”。从第二个字符开始每次遇到当前字符和前一个字符不一样就把碎片数量加一最后用字符串总长度除以碎片数量。我第一次做的时候想复杂了去构造了一个vector存每一段的长度再把它们平均。后来发现完全没必要一个计数器就够。这也是这套真题集的一个特点很多题看起来像“模拟题”但最优解往往只是一个小观察。2.4 游历魔法王国一道题串起树、贪心和动态规划题目大意魔法帝国有n个城市编号从0到n-1城市之间用n-1条无向边连接构成一棵树。小易从0号城市出发最多走L步每一步走一条边。他每到达一个城市就算访问过同一个城市重复经过只算一次问最多能访问多少个不同的城市。这道题是整套题里比较有区分度的一道。很多人看到树就紧张实际上核心在于一个很直观的贪心如果步数不是很多那就沿着某一条路径一直走到底访问到的城市最多如果步数非常多那就在某条最长路径走完之后用剩下的步数去“逛”其他分支。“最长路径”不是随便选一条而是从0号城市出发能走到的最深深度。这里我先提示一下正解不是求整棵树的直径而是求从0号根节点出发的最深路径这个细节很容易搞错后面我会专门推导。3. 最优解推导全过程从暴力想法到能AC的代码3.1 魔法币自顶向下倒推每次缩小一半魔法币的暴力做法是从0开始BFS每一步尝试机器1或机器2直到某个状态等于n。问题在于状态是指数级增长的n一旦超过10^9搜索空间完全不可接受。反过来看就简单了。假设当前硬币数是cur如果cur是奇数说明它一定是通过机器1从某个x变来的并且满足cur 2x 1所以x (cur - 1) / 2。如果cur是偶数说明它是通过机器2变来的x (cur - 2) / 2。每次倒推一步cur都会减小到原来的一半左右所以时间复杂度是O(log n)。string solve(long long n) { if (n 0) return ; if (n 1) return solve((n - 1) / 2) 1; return solve((n - 2) / 2) 2; }这里有两个要注意的点。第一n必须用long long因为题目有可能给到很大的数int会溢出。第二递归拼接字符串时要保证顺序是从第一次操作到最后一次操作所以倒推得到的机器编号要放在已有字符串的后面或者先递归再拼字符。3.2 相反数string反转与stoi的兼容性相反数最稳妥的写法就是字符串反转。C的stoi函数在转换时会自动跳过前导零所以不需要手动处理“0021”这类情况。int n; cin n; string s to_string(n); reverse(s.begin(), s.end()); int rev stoi(s); cout n rev endl;如果你不想用stoi也可以自己写一个循环从字符串开头开始res res * 10 (s[i] - 0)。使用这个写法前导零在数学上会被自然省略因为“0 * 10 0”还是0。关键点是不要把反转后的字符串直接当成数字输出否则会保留前导零导致格式错误。3.3 字符串碎片计数器只需要一个变量字符串碎片的做法是统计“相邻字符发生变化的次数加一”。从第二个字符开始遍历如果当前字符不等于前一个字符碎片数量加一。总长度除以碎片数量就是平均长度输出时保留两位小数。string s; cin s; int cnt 1; for (int i 1; i (int)s.size(); i) { if (s[i] ! s[i - 1]) cnt; } printf(%.2f\n, (double)s.size() / cnt);这里需要注意空字符串的情况但题目一般会保证字符串长度至少为1。另外如果使用cout输出浮点数默认精度可能不会保留两位小数所以这类题建议直接用printf格式化输出。3.4 游历魔法王国从根出发的最深路径加剩余步数折算游历魔法王国的正解分为两步。第一步求出从0号节点出发到最远叶子节点的边的数量记为maxDepth。这可以用一次DFS实现从0号节点开始遍历所有子节点深度取最大值加一。第二步根据步数L进行分类讨论。如果L maxDepth说明你最多只能沿着某一条路一直走访问的城市数量是L 1。因为从0出发走一步到达一个城市走L步最多经过L条边经过的节点数是L 1。如果L maxDepth说明你不仅能把从0到最深叶子的路径走完还会有剩余步数。先沿着最深路径走完已经访问了maxDepth 1个城市。剩下的步数是L - maxDepth由于访问其他分支时需要从主干上的某个节点进入分支再原路返回主干每一次来回需要2步只能多访问1个新的城市。所以额外可以访问的城市数是(L - maxDepth) / 2。最终答案取min(n, maxDepth 1 (L - maxDepth) / 2)因为城市总数只有n个不可能超过这个上限。def dfs(u, parent): depth 0 for v in g[u]: if v ! parent: depth max(depth, dfs(v, u) 1) return depth max_depth dfs(0, -1) if L max_depth: print(L 1) else: print(min(n, max_depth 1 (L - max_depth) // 2))这段代码适合用来理解思路但实际笔试如果n非常大递归DFS可能会爆栈。建议改成显式栈或BFS来求最大深度。另外为什么不能直接用全树直径因为起点固定是0你第一步只能从0出发选择一条边如果最长直径的另一端不在0这个方向你是没法直接沿着整条直径走的。所以必须求从0出发的最深路径。4. 现场笔试最容易翻车的五个细节都是血泪经验4.1 输入输出模式ACM模式下别用cout刷屏很多同学平时用LeetCode的函数式编程很顺手到了牛客这类ACM模式笔试连最基本的while(cin n)都不习惯。这套真题集合里的题目大多是单组输入但有些题会有多组数据或者需要你读完整行再处理。我踩过最蠢的坑是有一段调试用的cout输出忘了删结果本地没问题在线判题一直WA。后来才发现是多余输出干扰了评测比对。所以在提交前一定要仔细检查有没有残留的调试输出。4.2 数据范围n给到10^18时int会哭魔法币这道题n有可能给到很大的值。如果函数参数写成int递归计算(n - 1) / 2时也可能不会立即溢出但一旦n超过int上限直接就是错误的。相反数这道题如果n给到10^9反转后也可能超过int范围虽然很多评测不会卡这个点但用long long更稳妥。建议养成一个习惯看到题目里没有明确说明数据范围或者数据范围描述里出现“10^9”“10^18”这类字样一律用long long。不需要每次都用大数模板但至少不要让类型成为扣分点。4.3 递归深度不是所有倒推都像魔法币这么浅魔法币的递归深度是O(log n)非常浅完全不用担心爆栈。但游历魔法王国这种树上的DFS如果n是十万级递归深度可能达到十万层。C默认栈空间通常只有几MB递归太深会直接栈溢出。这时候可以把递归改成迭代用一个栈模拟DFS或者直接用队列做BFS求最大深度。我在做这道题的时候就因为递归爆栈卡了很久后来改成BFS才通过。4.4 多组用例的初始化cnt忘清零是头号错误字符串碎片这类题逻辑很简单但如果题目是多组输入你需要在每组输入前把计数器重置。很多人第一组AC第二组WA就是因为计数器是在循环外面初始化的第二组数据累加到了第一组的结果上。解决方法是把变量声明尽量放在循环体内部或者每次循环开始前显式初始化。这个习惯不只在网易笔试里重要在所有ACM模式笔试里都重要。4.5 浮点输出保留两位是硬性要求字符串碎片要求输出平均长度并保留两位小数。用printf(%.2f)最直接。如果你用cout默认的精度是6位有效数字可能输出2.25没问题但如果答案是2.50cout可能输出2.5判题系统会认为格式错误。浮点输出还有一个小坑除法操作要保证先转成double再除而不是两个整数相除取整。int / int在C里结果是整数直接丢掉小数部分后面printf再格式化也救不回来。5. 真题刷完之后怎么把这些题转化成笔试能力5.1 建立“考点—题目—错因”对照表刷完这套真题别急着把网页关掉。我建议拿一张表左侧写考点中间写题目右侧写自己的错因。比如魔法币对应“逆向构造”错因可能是“没想到倒推”相反数对应“字符串处理”错因可能是“前导零没处理干净”游历魔法王国对应“树上的最优路径”错因可能是“求成了整棵树的直径”。这样做的好处是一个月后回看这张表你能直接看到自己的知识漏洞地图而不是面对一堆AC过的代码发呆。准备秋招笔试时这张表比任何收藏夹都有效。5.2 用真题做限时模拟而不是零散刷这套题特别适合用来做限时模拟。找两个小时的完整时间段打开题目列表不看任何解析像真正笔试一样把每道题写完。做完之后再统一对答案、看题解。为什么要限时因为大厂笔试最大的敌人不是题目难而是节奏乱。很多人在一道题上死磕半小时导致后面简单题都没时间写。限时模拟能帮你建立时间分配的感觉比如遇到卡壳超过15分钟的题先标记跳过等简单题写完再回来。5.3 把老题当作新题的母题真题的价值不在答案本身而在它背后的“母题方法”。魔法币是“逆向构造”的母题相反数是“字符串反转与边界处理”的母题字符串碎片是“连续段统计”的母题游历魔法王国是“树上的贪心与步数折算”的母题。我在后续刷题中遇到很多类似题都会下意识去想能不能从最终状态倒推多出来的步数要不要除以2这个习惯就是从这套真题里养成的。吃透老题新题对你来说往往只是换了层壳。5.4 补充这套题没覆盖到的高频算法2018这套题覆盖了字符串、数学、构造、贪心、DP、树但还有一些高频考点没有出现比如并查集、二分答案、前缀和、单调队列、图的最短路。建议在刷完这套真题后按下面顺序补充字符串处理排序与贪心二分DFS/BFS动态规划并查集图论最短路径。这样才算把真题的价值放大到整个秋招。最后说一个我自己的习惯每次刷完一套真题我会把每道题的代码压缩成一个命名包含考点的文件比如magic_coin_reverse_push.cpp、string_piece_count.cpp。一个月后重新看这些文件名就能快速回忆起每个考点的核心套路。这个习惯帮我在后续几家公司的笔试里节省了大量复习时间。网易2018这套题是很好的开始希望你能把它真正吃透。
返回列表