☰
华为机试编程模拟题9:题型规则、算法考点与ACM模式实战详解
2026/9/26 20:17:36 网站建设 项目流程

你搜到“华为机试编程模拟题9”,大概率已经进入笔试备战阶段,不是随便刷题,而是想按机考的节奏来一遍闭环训练。这篇文章就围绕这套模拟题展开,讲清楚华为机试的题型规则、算法考点、ACM模式下的输入输出细节,以及我实际刷题和辅导中踩过的各种坑。内容既照顾刚接触机试的新手,也给已经刷过不少题、想加速提分的人参考。

这里要特别说一下:华为机试和普通算法题最大的差别在于,它既要考算法功底,又考临场输入输出处理。很多人不是不会做题,而是死在了环境与细节上。所以下面我拿一套高仿真实难度与题型的模拟题组,逐步拆解题型分布、算法考点、提交踩坑和备考节奏,希望能帮你在上考场之前把该踩的坑都先踩一遍。

1. 华为机试到底考什么:先搞懂规则再动手刷题

1.1 题型、分值与判题逻辑

华为机试普遍是三道编程题,整体难度从简单到难递进。不同批次、不同部门的分值配比会有差异,常见的是第一题100分、第二题200分、第三题300分,总分600分。判题不是只看有没有运行结果,而是用隐藏测试用例按点给分,所以部分通过也能拿到对应比例的分。

这意味着算法不完美的部分解法也能得分,尤其是第二题,只要思路正确、暴力枚举能过小数据用例,就千万不要空着。很多考生一看到第三题没有头绪就直接放弃整场,这其实很亏。机试的评分逻辑是“能拿一分是一分”,不是非黑即白的AC判定。

另外,考试时间一般控制在两个半小时左右,具体批次的时长会有出入。做题时需要自己控制节奏,最好把前面简单的题留出足够时间,别等到最后十分钟才开始写第一题。三道题是平铺在一个试卷里的,你可以自由选择做哪道,但提交后会以最后一次提交为准。

1.2 新系统、双机位C卷带来的变化

近一两年机考系统持续更新,网上常说的“新系统、双机位C卷”,主要还是围绕监考环境、题本抽取和防作弊机制展开。双机位要求你用电脑摄像头作为正面机位,另用手机从侧后方拍摄桌面和屏幕,考试前会扫码绑定机位;C卷/B卷更多是用来标记不同批次的题库,本质是同一套考点体系的乱序抽取。

这个变化对做题本身影响不大,但影响考试体验:你不可能像平时练习那样随时切出窗口查资料。因此我建议备考时就养成“纯手写+本地IDE”的习惯,不要依赖网络搜索题解和查函数签名。平时刷题时可以偶尔翻文档,但到了模拟训练里,必须把自己按在真实考试的环境里,逐步适应没有外部帮助的状态。

有些同学问双机位会不会误判,我的理解是,只要你的手机架设位置符合要求、桌面没有乱七八糟的电子设备,一般不会出问题。真正容易翻车的是那些过程中频繁切窗口、鼠标长时间停在监控区域之外的考生,系统后台一旦记录下来,后续申诉会非常麻烦。

1.3 为什么成套模拟题比随机刷题更管用

LeetCode的题质量高,但机试场景最大的敌人不是难度,而是不确定。成套模拟题的好处是,它能把分值配比、题目顺序、输入输出风格一次性暴露出来。我刷模拟题9的时候有个很明显的感受:前两道题难度不大,但输入格式不固定,容易在IO解析上浪费时间;第三题则考验我能不能快速想出搜索模型。

单刷算法题往往只练“解题”,练不到“读题-建模-编码-调试-提交”的完整链路。而机试并不是单纯比谁会写最优解,它比的是谁能用稳定的心态和熟练的代码风格,在有限时间内把该拿的分拿到。所以成套模拟题的训练价值,不只是让大家多几个题解,而是训练一种“考试肌肉记忆”。

2. 模拟题9的题目拆解:三道题分别考什么

下面这三道题不是官方原题,而是我拿历年高频考点和对“模拟题9”这类套卷的整体印象做的高仿还原,用来演示解题思路是够的。你可以把重点放在模型和应用上,不要纠结于题目叙述是否原文一致。

2.1 第一题(约100分):字符串统计与字典序

题目描述:输入一行由小写字母组成的字符串,长度不超过10000,统计每个字符出现次数,输出出现次数最多的字符。如果出现次数相同,输出字典序最小的字符。

这道题在考试里属于“保底题”,但保底题也有陷阱。很多人第一反应是哈希统计后再排序,或者直接调用max函数,结果忽略“字典序最小”这个平局规则。我先给出一个比较稳妥的写法:

import sys def main(): s = sys.stdin.readline().strip() if not s: return cnt = {} for ch in s: cnt[ch] = cnt.get(ch, 0) + 1 # 出现次数越多越靠前,出现次数相同则字典序小的靠前 ans = min(cnt.items(), key=lambda x: (-x[1], x[0]))[0] print(ans) if __name__ == "__main__": main()

这里的关键技巧是用一个元组同时比较两个维度。-x[1]让出现次数多的排在前面,x[0]在次数相同时让字母序小的排在前面。如果用max(cnt.items(), key=lambda x: x[1]),它只会返回第一个遇到的最大次数项,在平局场景下不保证字典序,十个样例里至少能撞出一个用例让你失分。

2.2 第二题(约200分):动态规划与滚动数组

题目描述:给定一个正整数数组nums,从中选择若干个不相邻的数字,使得和最大。输出这个最大和。数组长度不超过10^5,单个数字不超过10^9。

这是“打家劫舍”的变体,核心是动态规划。状态可以定义为:前i个元素能取到的最大和。对第i个元素,有两种选择:不选它,最大和等于前i-1个元素的最优值;选它,则第i-1个元素不能选,最大和等于前i-2个元素的最优值加上nums[i]。

import sys def main(): data = sys.stdin.read().split() if not data: return n = int(data[0]) nums = list(map(int, data[1:1 + n])) if n == 0: print(0) return prev2, prev1 = 0, nums[0] for i in range(1, n): cur = max(prev1, prev2 + nums[i]) prev2, prev1 = prev1, cur print(prev1) if __name__ == "__main__": main()

很多第一次写这道题的人容易犯两个错误。一个是把转移写成prev1 + nums[i],觉得只要在之前最优基础上加当前值就行,却忘了“不相邻”限制,导致相邻元素被同时选中。另一个是漏掉数组长度为1时的特殊情况,直接进入循环,虽然这段代码能处理,但如果你用数组形式记录dp,就一定要初始化dp[0]和dp[1]。

另外注意数据范围,单个数字和可能超过32位整数,Java和C++里要用long/long long,Python的int没有这个问题,但也要留意其他语言场景下的溢出。

2.3 第三题(约300分):图的遍历与连通块

题目描述:给定一个m乘n的01矩阵,1表示陆地,0表示水域,求最大连通块面积。连通规则是上下左右四个方向相邻,斜对角不算。

这题考察的是非常经典的图遍历模型。可以用DFS,也可以用BFS。机试环境下,我更推荐用栈模拟DFS,而不是系统递归,因为递归深度在极端数据下可能爆栈。下面是我写的模板:

import sys def main(): data = sys.stdin.read().strip().split() if not data: return idx = 0 m, n = int(data[idx]), int(data[idx + 1]) idx += 2 grid = [] for _ in range(m): grid.append([int(x) for x in data[idx:idx + n]]) idx += n visited = [[False] * n for _ in range(m)] dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)] ans = 0 for i in range(m): for j in range(n): if grid[i][j] == 1 and not visited[i][j]: stack = [(i, j)] visited[i][j] = True area = 0 while stack: x, y = stack.pop() area += 1 for dx, dy in dirs: nx, ny = x + dx, y + dy if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == 1 and not visited[nx][ny]: visited[nx][ny] = True stack.append((nx, ny)) ans = max(ans, area) print(ans) if __name__ == "__main__": main()

这里最关键的细节是“入栈前就标记visited”。如果在出栈时才标记,同一个格子可能被多个邻居反复加入栈,导致重复计算,甚至让复杂度从O(mn)退化到指数级。这个错误极其隐蔽,因为小数据跑起来正常,一旦矩阵变大,程序要么死循环,要么超时。

如果你用递归,请记得在main入口设置sys.setrecursionlimit(1000000),但说实话,对于矩阵规模达到1000乘1000的情况,递归依然有风险。直接用栈是更稳的选择。

2.4 三道题的难度递进逻辑

机试的三道题,不是随便凑的。第一题要保证大部分人不至于0分,通常考字符串、哈希、排序;第二题筛掉只会暴力的人,通常考贪心、DP或前缀和;第三题再挑一波建模能力,常见的图遍历、状态搜索、最短路都会出现在这里。模拟题9也保持了这个节奏,所以刷的时候不要跳过第一题直接冲第三题,容易漏掉对读题和IO细节的训练。

这套难度递进其实对应的是岗位合格率的漏斗逻辑。第一题是基础门槛,第二题是区分度,第三题是冲刺高分的关键。如果目标只是通过,把第一题和第二题吃透,第三题拿部分分,通常就够了。但如果想确保稳过,第三题必须有完整思路。

3. 核心算法考点逐个击破

3.1 动态规划:状态定义是灵魂

以第二题为例,很多人一看就知道是打家劫舍的模板,但为什么状态要定义成“前i个元素的最大和”,而不是“以第i个元素结尾的最大和”?原因在于后者要求最后必须选第n个元素,答案失去通用性。状态定义错了,后面怎么写转移方程都别扭。

动态规划的本质是“用已知推未知”,你必须找到一个无后效性的状态空间。什么是无后效性?就是当前状态一旦确定,后续决策只依赖当前状态的值,而不依赖之前是通过哪条路径走到这里的。想清楚这一点,DP题基本就成功了一半。

常见错误还有:初始化时把dp[0]设成nums[0]而不是考虑空状态;长度n等于1或2的特判漏掉;用int存结果导致溢出。这些都在真实考试里出现过。刷DP题时,我建议每道题都手写一遍转移方程,再对照代码,不能只在脑子里想。

3.2 DFS/BFS:矩阵遍历的通用写法

第三题的解题步骤其实可以在三分钟内默写出来:方向数组、visited数组、栈或队列、四邻域检查。真正容易错的地方不在搜索,而在去重。前文已经强调过,入栈前就要置true,这里我再补充一个经验:二维坐标尽量用元组入栈,会比字符串拼接再解析快得多,代码也更清晰。

方向数组统一用dirs = [(1,0), (-1,0), (0,1), (0,-1)],不要为了省事只存四个字符串。输入很大时,这种微小的统一能增加代码稳定性。还有,当矩阵规模达到上千时,Python的for循环本身偏慢,可以考虑少做一次无意义的越界判断,比如先把数组边界扩展一圈,四邻域直接用下标访问,也能明显提升速度。

3.3 字符串题:那些“不是考算法”的坑

第一题表面在考哈希统计,实际在考“平局时按字典序最小”。很多人用max函数,结果在a和b出现次数同为3的时候,输出了错误结果。这个用例在题目里往往不会给出,只会隐藏在你能跑对大部分case但总有一两个过不去的尴尬局面里。

更恶心的是一些题会在字符串后面偷偷带\r,在Windows上用split()没问题,但用readline().strip()可能没去掉\r。稳妥起见,读入统一用sys.stdin.read().split()对单词或数字组成的输入很安全;如果题目明确要求保留空格,就老老实实用rstrip('\n')代替strip()。字符串题的坑通常不在算法,而在你如何处理这些看不见的空白字符。

4. ACM模式实战:输入输出与提交细节

4.1 三种语言的输入输出模板

ACM模式下没有封装好的函数供调用,必须自己处理标准输入和标准输出。下面是我常用的模板,能覆盖大多数场景。

Python版本:

import sys def solve(): data = sys.stdin.read().split() if not data: return n = int(data[0]) arr = list(map(int, data[1:1 + n])) # 业务逻辑 if __name__ == "__main__": solve()

Java版本:

import java.io.*; import java.util.*; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); int n = Integer.parseInt(st.nextToken()); long[] arr = new long[n]; st = new StringTokenizer(br.readLine()); for (int i = 0; i < n; i++) { arr[i] = Long.parseLong(st.nextToken()); } // 业务逻辑 } }

C++版本:

#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; vector<long long> a(n); for (int i = 0; i < n; i++) { cin >> a[i]; } // 业务逻辑 return 0; }

Java里一定要用BufferedReader,不要用Scanner,后者在数据量大时慢得离谱。C++里那两行IO优化几乎是必须的。Python里多数情况下sys.stdin.read().split()是最快的批量读法;如果一行行读反而容易因为readline的换行符处理出错。

4.2 边界条件与防御性输入处理

ACM模式下,输入里可能有多余空格、空行,也可能数据在最后一行没有换行符。你要是直接用流式输入一般没事,但遇到第一行是整数、第二行是字符串的混合情形,就得注意换行符残留。

我通常的做法是能读数字尽量用read().split()全部切好,再按下标取。对于字符串类型的行,单独用readline().rstrip('\n')。这两种方式混用能覆盖绝大多数题目。

边界值越多测越好:n=0、n=1、最大值、重复元素、全部相同、从大到小等。举个简单的例子,排序题里如果题意没说要稳定排序,却在答案里默认稳定,可能在特殊用例上翻车。防御性编程不是说代码写得越复杂越好,而是提前把输入的各种可能性想清楚,用最小的成本处理掉。

4.3 复杂度控制:从超时到AC

100分题的数据范围通常很小,暴力也能过;200分题的数据范围就要求你至少写出O(n log n);300分题很可能出现大规模图或搜索,要注意剪枝和空间优化。

拿第三题来说,递归DFS在Python里即使设置了sys.setrecursionlimit(1000000),遇到1000乘1000的全1矩阵也可能因为调用栈太深卡顿。用栈模拟DFS,或者用collections.deque做BFS,可靠性更高。Java和C++也有类似问题,递归层数超过系统栈上限会直接爆栈。

复杂度优化不是炫技,而是针对数据范围做的合理取舍。如果题目说数组长度不超过100,那O(n^2)完全没问题;如果是10^5,就老老实实想O(n log n)或O(n)。刷题时养成看数据范围的习惯,比盲目追求最优解重要得多。

5. 常见问题与排查技巧实录

5.1 本地能跑,提交0分

我在带人刷题时,遇到最多的情况就是“本地跑样例通过,一提交就是0分”。这个现象背后的原因五花八门,我整理了一个速查表:

现象可能原因排查方法
本地样例通过,提交0分输出格式多了空格或换行复制输出到记事本逐字符核对
第一行读取失败输入存在空行,你却用readline改用read().split()整体切分
部分用例超时用了O(n^2)或重复计算看数据范围,优化双循环
结果溢出int范围不够改用long/long long
编译错误类名不是MainJava确认public class Main
运行时错误数组越界检查n=1时的特殊分支

也有一种情况是题目要求处理多组输入,你用固定格式只处理了一组。虽然大部分华为机试题是单组输入,但还是建议在所有read类模板里加上EOF循环兼容,以防模拟题系统有特殊要求。

5.2 超时、内存溢出的排查思路

遇到超时不要先想着换语言,先把代码里的print改用sys.stdout.write,把cin和cout加ios::sync_with_stdio(false),把Java的Scanner换成BufferedReader。很多时候瓶颈就在IO而不是算法。我见过有人明明用了O(n log n)的排序,却因为输出时一次次print导致超时,这种替换只要一轮就能解决。

内存溢出通常是数组开太大。有些题给的是二维矩阵,你说不定能压缩成一维滚动数组;实在压缩不了,再看是不是可以边读边处理,不用全部存下来。如果这两步都做不了,那大概率是算法模型选错了,应该回到状态设计或搜索剪枝层面去优化。

5.3 双机位环境下的备考温馨提示

新系统采用双机位后,手机要架在侧面后方,桌面摆上台灯保证画面清晰。考前把电脑上的弹窗、广告、消息提醒全部关掉,浏览器插件能禁用就禁用,免得摄像头或录屏软件触发非预期弹窗。开始答题后尽量不切出IDE,这是对自己负责,也不会因为误操作留下可疑记录。

另外一定要提前在模拟环境里练习一次。不同系统之间的编辑器、快捷键、自动补全差距很大,有的环境连代码格式化都没有。你要是第一次进去,光适应界面就可能浪费十分钟。我自己第一次用不熟悉的在线编辑器时,连缩进都乱了,浪费了宝贵的调试时间。

6. 模拟题9的刷题节奏与复盘建议

6.1 按真实考试节奏卡时间

刷模拟题9时,给自己设定一个完整的倒计时,中间不暂停、不查资料、不接电话。前10分钟浏览三题,判断哪题好拿分,不要在第三题死磕到现在连第一题都没交。

我的习惯是:先做第一题,拿到保底分;第二题如果20分钟没有完整思路,先写暴力版本拿部分分,不要一上来就追求最优解;第三题留足30分钟以上,因为它是真正拉开差距的地方。这里要特别强调,暴力版本不是放弃治疗,而是用最直接的方式枚举所有可能,确保在数据量小的时候能拿分。

6.2 复盘时重点看什么

复盘不要只看标准答案,重点记录三个东西:

  • 哪类题读题慢:建议专项练习描述长的模拟题。
  • 哪类题有思路但代码写不顺:多背输入输出模板,多练手写代码。
  • 哪类题看题解才做出来:这就是你的知识盲区,列进下一轮刷题清单。

我刷完一套模拟题后,会花至少半小时复盘。每题都把解题时间、卡点、错误原因写下来。别小看这几行记录,它能帮你在最后一轮冲刺时快速定位薄弱点,而不是重新翻几十页题解。

6.3 我的几个实际体会

最后说点旁观者视角的体会。我在实际带人刷题时发现,最容易翻车的人不是不会算法,而是平时习惯在LeetCode核心代码模式里写函数,到了机试要自己处理输入输出就懵了。所以哪怕你只刷这一套模拟题9,也一定要在本地IDE里,用标准输入标准输出的方式完整跑通,再把结果贴到在线判题里。

还有一个细节是,判题时不要为了省事只测样例。三道题我都习惯多测四五个自己构造的边界用例,尤其是空输入、最大值、全相同、不存在答案的情况。这十分钟看似浪费,却能省下反复提交扣分的尴尬。

如果你能把模拟题9当成一次正式考试来对待,把错误真正吃透,这套题的价值会比闷头刷五十道LeetCode更大。考试考的不只是你会不会,更是你稳不稳。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询