如果你也在准备华为机试我建议你把模拟题系列认真刷一遍特别是这套题。我前几天刚把编程模拟题6完整过了一遍说实话这套题比很多网上流传的真题更值得做。它把字符串处理、滑动窗口、动态规划这几个高频考点全部覆盖到了而且题目设置得很贴近真实机试的节奏。无论你是刚开始接触华为OD机试还是已经刷过一些题想查漏补缺这套模拟题都能帮你校准备考方向。我刷完之后最大的感受是华为机试的难点不在题目本身有多难而在于你在限定时间内能不能又快又稳地把三类题做出来。模拟题6设计得很有代表性所以我想把整套题的拆解思路、代码实现和踩坑记录完整分享出来给后面备考的朋友一个参考。1. 这套模拟题背后的考核逻辑先看清机试在筛什么人在讲题目之前必须先搞清楚华为机试为什么这么考。很多人一上来就刷题刷了两个星期还是没底就是因为没看懂出题人的意图。华为机试本质上是在筛选两类能力第一类是代码基本功你能不能把思路干干净净地落地成可运行的代码第二类是问题建模能力面对一个带业务包装的描述你能不能快速识别出它到底在考哪个经典算法。华为OD机试采用新系统之后很多考场是双机位C卷模式也就是说除了电脑屏幕之外还有第二机位监控整个考试环境。卷子分为100分和200分两档题总分一般是400分。150分是大多数岗位的及格线但这个线不是固定的跟你投的部门、岗位等级都有关系。模拟题6的题型分布就是按这个标准来设计的两道100分题一道200分题整体难度曲线是先易后难。很多人容易犯一个错误就是觉得100分的题可以随便敷衍把时间都留给200分的压轴题。我个人的建议恰恰相反100分题必须拿到手而且尽量拿满分。因为200分题往往存在一种情况你思路对了但某一个边界条件写错导致大量测试用例挂掉。这时候如果100分题再因为粗心丢分总分就很危险了。模拟题6的前两道题就是用来练这种稳扎稳打的手感的。另外还要注意华为机试的代码是提交到在线评测系统里不是像面试那样口头讲讲思路就行。这意味着你对输入输出格式的处理必须非常严谨。很多人在本地跑得好好的一提交就报错八成是卡在输入输出的细节上。模拟题6里也有些这类隐藏的坑后面我会单独拿出来说。从这个角度看刷模拟题不仅仅是在刷算法更是在刷一套完整的考试操作流程。等你上了真考场你会发现所有操作都已经肌肉记忆了真正要留给大脑思考的时间全花在200分那道题上这才是最终合理的节奏。2. 三道题的考点拆解字符串、滑动窗口、贪心里的门道模拟题6的三道题我一个个拆开讲。每一道题我都会说明它对应的考点、出题人想考你什么、以及最容易被忽略的细节。这样你以后再碰到同类题就知道往哪个方向想了。2.1 字符串解压不能只想着看到字母就拼字符串第一题是一个字符串解压问题输入一段压缩后的字符串比如a3b2c1要求输出解压后的完整字符串也就是aaabbc。压缩规则很好理解每个字符后面跟一个数字表示这个字符重复几次。我看完题的第一反应是这题太简单了直接遍历遇到字母就记录然后读数字循环拼接。但如果你也这么想大概率会掉进一个坑里题目没有说数字一定是一位数。也就是说输入完全可能是a10b2这种情况下你要解压出10个a。很多人在这一步直接用单个字符读数字结果遇到多位数就出错。正确处理方式是边读边累加。读完字母之后用while循环不断读取数字字符每读一位就把之前的数字乘10再加上当前位。这样无论数字是几位都能正确处理。还有一个隐藏的边界情况是a0b2意思是字符a重复0次也就是什么都不输出。这种用例看起来像故意刁难但其实考的就是你思维的严谨程度。这道题的考点本质是字符串的解析与重建关键词是解析。华为机试里大量题目都长这个样子给你一个格式比较规整的字符串先按照某种规则解析再按照另一种规则输出。你不需要用什么复杂的算法纯粹考察对字符串下标、拼接、ASCII转换这些基本功的熟练度。代码量不大但要求一次写对。我刷题的时候习惯先写最朴素的版本再回头检查边界。朴素版本就是遍历、解析、拼接不搞花哨优化。这道题里的所有细节比如多位数、0次重复、空串输入其实都可以通过自测用例覆盖。后面我会专门列一个自测用例清单。2.2 翻转0的最长连续1子数组不要一上来就改原数组第二题是一道经典的滑动窗口变体题面大概是给你一个由0和1组成的数组最多可以翻转k个0为1求翻转后最长的连续1子数组的长度。这个题目有很多名字有人叫最大连续1的个数有人叫滑动窗口内的0计数。我看到这道题的第一个念头是能不能真的把数组里的0改成1反正最多k个翻转之后求最长连续1。但这个思路在编程实现上很麻烦因为你不知道应该翻哪几个0要试的窗口很多。正确的做法是不要真的去翻转而是维护一个滑动窗口让窗口内0的个数始终不超过k窗口的长度就是当前可能的连续1长度。具体思路是这样的用两个指针left和right维护窗口right不断向右扩展。每遇到一个新的0就把窗口内的0计数器加一。如果0的个数超过了k说明窗口太大了left需要向右收缩直到0的个数重新小于等于k。在收缩的过程中如果left离开的是一个0计数器要减一。每次调整完窗口之后用当前窗口长度去更新答案。这个思路的本质是把最多允许k个0这一约束转化成窗口内0的数量上限。我在做模拟题6的时候差点犯一个错误就是只更新了right没有维护left结果窗口越滑越大。记住滑动窗口题最核心的部分就是搞清楚left什么时候收缩以及收缩的时候需要更新哪些统计信息。另外这道题的时间复杂度是O(n)空间复杂度是O(1)在机试环境里属于非常标准的解法。如果有人在面试或者讨论里说这题可以用动态规划做也不是不行但没有滑动窗口直观。机试就是求稳哪个容易理解不容易写错就用哪个。2.3 最少跳跃次数贪心还是动态规划得想明白第三题是整张卷子的压轴描述大概是给你一个数组arr每个元素表示从当前位置最多可以往后跳多少步假设你从下标0出发问到达最后一个位置最少需要跳几次。数组保证一定可以到达末尾。看到最少两个字很多人第一反应是动态规划。确实可以定义dp[i]表示到达第i个位置的最少跳跃次数然后从前往后扫描转移方程大概是dp[ij] min(dp[ij], dp[i]1)其中j的取值范围是1到arr[i]。但这样做的时间复杂度是O(n乘以最大步长)在数据量大的时候可能会超时。更优的解法是贪心。思路是维护三个变量当前跳数step当前这一跳能到达的最右边界curEnd以及从现在位置出发能到达的最远位置curFarthest。每遍历一个位置就更新curFarthest为max(curFarthest, i arr[i])。当i到达curEnd时意味着这一跳已经走到了尽头必须再跳一次step加一同时把curEnd更新为curFarthest。如果curEnd已经覆盖了最后一个位置就提前退出。这个贪心的关键在于什么时候必须跳的判断。很多讲解会说curEnd保存的是当前步数内能到达的最远位置但代码一多就容易绕晕。你可以换个方式理解你在某一段范围内可以选择任意一点作为起跳点起跳点能去的最远位置决定了下一跳的边界。当你在当前跳范围内遍历完所有点时你实际上已经找到了这一跳范围内所有点能到达的最远位置所以必须跳出去这就是贪心最优的体现。我在模拟题6里选择的解法是贪心因为它在O(n)时间内解决而且边界条件相对清晰只有curEnd和curFarthest两个变量需要维护。相比之下动态规划虽然思路更好想到但循环嵌套加上转移条件反而容易在机试的紧张状态下写错。这里有个经验200分题不要纠结于最优解是不是贪心如果你只能稳定写出动态规划那就用动态规划至少能拿大半分数。但平时训练还是要两种方法都掌握。3. 参考实现与自测用例直接从能跑的代码里学光讲思路不贴代码等于没说。我把三道题的参考实现都写出来用的都是C因为华为机试的主流语言之一就是C。你写成Java或Python思路完全一样只是语法不同。每段代码我都会标注几个关键点方便你对位检查。3.1 字符串解压的边界处理实现#include iostream #include string using namespace std; int main() { string s; cin s; string res; int i 0; while (i (int)s.size()) { char c s[i]; int num 0; while (i (int)s.size() isdigit(s[i])) { num num * 10 (s[i] - 0); i; } res.append(num, c); } cout res endl; return 0; }这段代码的关键就是内层while处理多位数。我特别提醒一下res.append(num, c)这个函数如果num为0就什么都不加这正好符合题目中重复0次的语义。如果你用循环来拼接记得加上是否num为0的判断否则可能多输出一次。3.2 滑动窗口翻转0实现#include iostream #include vector #include algorithm using namespace std; int main() { int n, k; cin n k; vectorint nums(n); for (int i 0; i n; i) { cin nums[i]; } int left 0, right 0; int zeroCount 0; int ans 0; while (right n) { if (nums[right] 0) { zeroCount; } while (zeroCount k) { if (nums[left] 0) { zeroCount--; } left; } ans max(ans, right - left 1); right; } cout ans endl; return 0; }这里的输入格式我按第一行n和k第二行n个数来处理实际题目可能不同但核心是窗口内0的计数。我写这题的时候特别留意了left收缩的时机必须在zeroCount超过k之后才开始收缩而且收缩要持续到zeroCount小于等于k为止不是只收缩一次。3.3 最少跳跃次数贪心实现#include iostream #include vector using namespace std; int main() { int n; cin n; vectorint arr(n); for (int i 0; i n; i) { cin arr[i]; } if (n 1) { cout 0 endl; return 0; } int step 0; int curEnd 0; int curFarthest 0; for (int i 0; i n - 1; i) { curFarthest max(curFarthest, i arr[i]); if (i curEnd) { step; curEnd curFarthest; if (curEnd n - 1) { break; } } } cout step endl; return 0; }注意循环只走到n-2也就是最后一个位置的前一个位置。因为最后一个位置是终点不需要再从这里起跳。如果n1一开始就在终点答案就是0。这个提前返回很容易漏掉。3.4 自测用例清单反复使用直到形成条件反射我把这三道题应该测的用例全部列出来。在正式机试时写完代码不要急着提交先花两分钟把这类用例在脑子里过一遍。题目用例预期输出说明字符串解压a3b2c1aaabbc基础用例字符串解压a10b2aaaaaaaaaabb多位数压缩字符串解压a0b2bb0次重复字符串解压ab2abb数字为1时不下标混乱滑动窗口数组 1,1,0,0,1,1k140计数边界滑动窗口数组 0,0,1,1,0,0k02k为0时等价于直接求最长连续1滑动窗口数组全1k3n全1场景最少跳跃2,3,1,1,42经典用例最少跳跃1,1,1,13每步跳1最少跳跃3,2,1,0,12有0步的场景注意能否到达这些用例的价值不在于多而在于覆盖每一种可能的边界。以我的经验来看机试中70%的常见错误都可以通过建立这套自测体系提前拦截掉。4. 从模拟题到真题的迁移考点不变只换包装华为机试有一个非常明显的特点同一类考点每年换着各种业务场景往外抛。你如果只记住了某一道题的题面下一次遇到就不会做那就等于白练。刷模拟题6真正的价值是帮你总结出一套题型迁移地图。我刚把三道题的考点抽象一下字符串解压属于字符串解析类。相似题有IP地址转整数、日志格式解析、压缩后的解压计数、括号匹配里的表达式值计算。华为特别喜欢出这种给你一段格式特定字符串按规则转换的题。翻转0求最长连续1属于滑动窗口类。相似题有无重复字符的最长子串、定长子数组的最大平均值、最小覆盖子串、长度最小的子数组。滑动窗口的核心模式就是left和right两指针加上一个窗口内统计量。最少跳跃次数属于贪心/区间覆盖类。相似题有会议室安排、无重叠区间、分发饼干、加油站。这类题最常见的就是找最值而且要证明贪心选择是对的。迁移的关键是识别信号词。看到连续子数组最多最少这些词就应该在脑内亮起对应的算法灯。比如题目说最多可以修改k个大概率是滑动窗口说最少跳几次最少步数最少硬币大概率是动态规划或贪心。信号词不是100%准确但至少能帮你快速锁定一个候选方向。我在辅导别人的时候经常让他们做一个动作每刷完一道题不要急着看下一题停下来写一行注释——这道题如果我换个场景会变成什么比如说字符串解压的题面换成给出一段加密后的用户ID规则还原原始ID考点还是一样的。这样练多了之后考场上读到题干的第三句话你已经能感觉到这道题在考什么了。模拟题6之所以有参考价值就是因为它每一道题都选得很典型属于那种出题人只要改场景就能再出十道的底子题。把底子题的解法吃透其实是在用一题的时间复习十题。5. 机试环境操作细节输入输出、自测和提交流程的坑这部分是很多人忽略但最容易丢分的地方。算法题你会做思路也对但操作环节出问题同样功亏一篑。我整理了一些实际机试中会遇到的隐性坑模拟题6的练习过程也暴露了其中几个。首先是输入格式。华为机试的输入一般是标准输入可能有多个测试用例也可能只有一个。你要根据题目描述判断是否存在多组输入。模拟题6三道题都是单组输入但真实考试中有些题的输入行数或者格式会变化。一道保险的做法是先读取第一行确认数据规模再根据规模读取后续内容。不要假设输入永远在一行里更不要假设每个数字一定用空格分隔有可能换成逗号或者分号。其次是输出格式。多一个空格、少一个换行都可能导致Wrong Answer。有些题目要求输出结果保留两位小数有些要求不换行输出还有些要求按字典序排序后输出。这些细节在题目描述里通常写得很清楚但考场上容易忽略。我建议用最快的速度把题目描述扫一遍标注输出要求再开始写代码。然后是自测。华为机试的在线评测系统通常支持你自己输入测试用例也就是你可以在提交前先用自己的数据验证代码。模拟题6的代码写完之后我要么用题目给的示例输入跑一遍要么用上一节列出的自测用例跑一遍。这个过程花费的时间不超过五分钟但能避免很多因为边界条件导致的全盘崩溃。最后是提交策略。如果一道题你写了很久还是不对不要死磕。200分题如果做不出来至少先把暴力解法写上哪怕只能过一部分用例也能拿到一部分分数。机试是按用例给分的不是零分或者满分两个选项。我见过很多人在第三题上死磕到底结果第一二题的用例没有充分验证送了不少分。合理的策略是先把三题都做出来一版再回头优化没通过的用例。还要提醒一点的是代码规范。虽然机试的评测系统不检查你的代码风格但清晰规范的代码能让你自己在调试的时候更快发现问题。变量命名尽量有意义比如windowStart、maxLen而不是a、b、c。遇到要调试的中间结果善用cerr或者print语句。有些人觉得print会影响性能但其实在自测阶段无所谓提交之前清理掉就行。6. 备考冲刺建议实战后的复盘与节奏管理最后聊点备考节奏上的体会。模拟题6刷完之后我的建议是不要马上刷模拟题7而是花一两天时间把这三道题重新默写一遍。默写的意思不是背代码而是在不参考任何资料的情况下从头开始写出可以运行的代码。这个过程能真正检验你到底是理解了还是看懂了。看懂了和能写出来之间隔着一条巨大的鸿沟只有亲手写才能跨过去。默写完之后我还会做一件让很多人觉得多余的事给每一道题写一份错误分析报告。格式很简单哪个地方卡住了、哪个边界没考虑、哪个函数用错了、为什么错。比如我在模拟题6里犯过一个错字符串解压时把isdigit直接用在s[i]上但忘记i的类型转换导致char强转成负数触发未定义行为。这种东西如果不记录下次碰到同样的问题还是会栽。备考的时间规划方面我建议把最后一周分成两段。前半段刷过去的错题和模拟题中没做出来的题目每个题型至少过两遍。后半段每天上午固定做一套完整的模拟题严格按照考试时长来中间不中断训练考场的注意力分配。晚上不做新题只复盘当天的错误和超时点。这不仅是在练算法也是在做考试节奏演练。最后的最后说点心态上的事情。华为机试的门槛没有想象中那么高但它确实会筛选掉那些代码功底不扎实和心态不稳的人。模拟题6让我比较欣赏的一点是它的难度梯度非常合理至少不会一道题做到一半就让你想放弃整场考试。如果你刷到某道题卡了很久别急着怀疑自己先跳过把能拿的分都拿到再回头做。这个策略听起来很朴素但我在真考场上体会到过它的价值。我用这套方法刷完模拟题6再回顾整个机试准备过程最大的收获是意识到模拟题的模拟二字其意义不只是模拟题目更是模拟一场真实考试的完整链路——审题、建模、编码、自测、提交策略。很多人把刷题窄化成了做题其实丢了更大的目标。希望这篇拆解能帮你在备考路上少走一些弯路用更少的题量拿到更稳的分数。
