华为机试的核心特点
- OJ系统严苛:使用华为自研的OJ平台,对代码的正确性、效率、鲁棒性要求极高,一个微小的边界条件错误或效率瓶颈都可能导致部分测试用例不通过。
- 时间压力大:通常有3-4道题,总时长为2-3小时,这意味着平均每道题的思考和编码时间非常有限,要求快速进入状态。
- 题量大,综合性强:题目通常不是简单的模板题,而是需要将多个知识点(如数据结构、算法、字符串处理、数学计算)融合起来解决一个实际问题。
- 偏爱基础与底层:相比于一些互联网公司喜欢考新颖的“智力题”或“脑筋急转弯”,华为更偏爱考察计算机科学的基础知识,尤其是数据结构和算法的深度应用。
- 注重代码规范:虽然OJ主要看结果,但良好的代码风格(命名、注释、结构)也是工程师素养的体现,在面试环节可能会被问到。
主要考察的知识点
可以大致分为以下几类,你需要对每一类都有扎实的掌握。
数据结构
- 字符串:绝对的重点和难点,包括字符串匹配、反转、分割、转换(如十六进制转十进制)、处理大数(用字符串模拟加减乘除)等。
- 数组/列表:排序(快排、归并、堆排)、查找(二分查找)、双指针、滑动窗口、前缀和、差分数组等。
- 链表:反转、合并、找环、相交、删除节点等经典操作必须滚瓜烂熟。
- 栈与队列:实现特殊功能(如用栈实现队列)、括号匹配、表达式求值(逆波兰表达式)。
- 树与图:
- 树:二叉树的遍历(前中后序,层序)、最近公共祖先、路径和、判断平衡二叉树等。
- 图:较少直接考,但图的遍历(BFS/DFS)思想常用于解决网格、迷宫类问题,最短路径算法(Dijkstra, Floyd)也可能出现。
- 哈希表:解决查找、去重、统计频率等问题,是提高效率的利器。
算法思想
- 排序算法:必须手写实现,特别是快速排序。
- 查找算法:二分查找及其变种。
- 递归与回溯:解决排列组合、子集、迷宫路径、N皇后等问题。
- 动态规划:难点中的难点,常见类型有:背包问题(0-1, 完全, 多重)、最长递增子序列、编辑距离、路径问题(不同路径、最小路径和)等。
- 贪心算法:如区间调度、霍夫曼编码、找零问题等,需要证明贪心策略的正确性。
- 深度优先搜索 & 广度优先搜索:解决树、图、网格类问题的核心工具。
数学与逻辑
- 基础数学:素数判断、最大公约数、最小公倍数、排列组合公式。
- 位运算:灵活使用
&, ,^, ,<<,>>可以高效解决很多问题,如判断奇偶、交换两数、求二进制中1的个数等。 - 逻辑推理:一些题目本身就是一个逻辑谜题,需要先抽象成数学模型或算法模型。
高效解题策略
在高压环境下,清晰的策略比蛮干更重要。
-
快速审题,明确要求:
- 输入是什么?(数据类型、格式、范围)
- 输出是什么?(数据类型、格式)
- 有没有特殊的边界条件?(如空输入、单元素输入、负数、0等)
-
分解问题,选择方案:
- 这道题的核心是什么?是排序、是遍历、还是状态转移?
- 时间复杂度和空间复杂度的要求是什么?这决定了你能用哪些算法,O(n²)的算法可能只能通过部分小数据,而O(n log n)或O(n)的才能通过全部。
- 优先选择自己最熟悉、代码最短、最不容易出错的算法。
-
模块化编码,边写边测:
- 不要一次性写完一个几百行的函数,将大问题拆成小函数(如
is_prime(),quick_sort()),然后逐个实现和测试。 - 用简单的测试用例(如
[1, 2, 3])验证你的函数是否工作正常。
- 不要一次性写完一个几百行的函数,将大问题拆成小函数(如
-
处理边界条件:
- 这是导致“部分通过”的主要原因,在写完主体逻辑后,专门思考一下各种边界情况:
- 输入为空或null怎么办?
- 数组只有一个元素怎么办?
- 循环的初始值和终止条件是否正确?
- 数组访问是否越界?
- 这是导致“部分通过”的主要原因,在写完主体逻辑后,专门思考一下各种边界情况:
-
时间管理:
- 如果一道题卡住了超过15-20分钟,果断跳到下一题,机试的目标是得分最大化,不是解决所有难题。
- 完成所有有把握的题目后,再回头攻克难题,有时解决后面的题会给你带来新的思路。
经典真题示例与解析
以下是一些具有代表性的题目类型,你可以感受一下华为的风格。
示例1:字符串处理(高频)
** 输入一个字符串,包含字母和数字,要求将其中所有的小写字母转换成大写字母,并将所有数字字符转换成对应的英文单词(如 '1' -> "one", '2' -> "two", ...),最后输出处理后的字符串。
输入: "hello123" 输出: "HELLOonetwothree"
考察点: 字符串遍历、条件判断、哈希映射。
思路:
- 创建一个数字到英文单词的映射字典,
{'1': 'one', '2': 'two', ...}。 - 遍历输入字符串的每一个字符。
- 判断字符类型:
- 如果是小写字母 (
char >= 'a' && char <= 'z'),则用大写字母替换。 - 如果是数字 (
char >= '0' && char <= '9'),则从字典中取出对应的英文单词拼接到结果中。 - 其他字符(如大写字母、标点)保持不变。
- 如果是小写字母 (
- 返回最终拼接的字符串。
示例2:数组与双指针(高频)
给定一个已排序的数组 nums 和一个目标值 target,在数组中查找两个数,使得它们的和等于 target,假设每个输入有且仅有一个解**,并且你不能使用相同的元素两次,返回这两个数的下标(从1开始)。
输入: nums = [2, 7, 11, 15], target = 9
输出: [1, 2]
考察点: 已排序数组的特性、双指针法、哈希表法。
思路(双指针法,最优):
- 因为数组已排序,所以可以利用这个特性。
- 初始化两个指针,
left指向数组开头(索引0),right指向数组末尾(索引len(nums)-1)。 - 循环,直到
left和right相遇:- 计算
sum = nums[left] + nums[right]。 sum == target,找到了,返回[left+1, right+1](注意题目要求下标从1开始)。sum < target,说明和太小了,需要增大和,因此将left指针向右移动(left++)。sum > target,说明和太大了,需要减小和,因此将right指针向左移动(right--)。
- 计算
- 由于题目保证有解,循环内一定会返回。
示例3:动态规划(中等难度)
** 给定一个非负整数数组 nums,你最初位于数组的第一个位置,数组中的每个元素代表你在该位置可以跳跃的最大长度,你的目标是使用最少的跳跃次数到达最后一个位置,假设你总是可以到达最后一个位置。
输入: nums = [2, 3, 1, 1, 4]
输出: 2
考察点: 贪心思想(常被归类为DP的一种贪心解法)、问题建模。
思路(贪心算法):
- 我们维护三个变量:
jumps:记录已经跳跃的次数。current_end:当前这一跳能够到达的最远边界。farthest:在遍历当前区间时,能跳到的最远位置。
- 遍历数组(除了最后一个元素,因为到达最后一个元素时就结束了):
- 更新
farthest为max(farthest, i + nums[i])。 - 如果当前位置
i到达了current_end,意味着必须进行一次跳跃了。- 将
jumps加一。 - 将
current_end更新为farthest,这一跳能到达的新边界。 current_end已经能到达或超过最后一个位置,就可以提前结束。
- 将
- 更新
- 返回
jumps。
如何准备
- 打好基础:重新系统学习数据结构和算法,重点是理解其原理和时间/空间复杂度分析,而不是死记硬背代码。
- 专项练习:
- 字符串:在LeetCode上刷所有 "Easy" 和 "Medium" 难度的字符串题,直到能快速写出正确代码。
- 数组:重点练习排序、双指针、滑动窗口、前缀和。
- 动态规划:从简单的斐波那契数列开始,逐步攻克背包、路径等经典问题,这是最花时间但回报也最高的部分。
- 刷真题:
- 牛客网:这是华为机试的主要平台,上面有大量的华为历年真题和模拟题,务必把上面的“华为专项练习”刷一遍。
- LeetCode:虽然不是华为原题,但LeetCode上的题目能很好地锻炼你的思维和编码能力,可以重点刷 "Top Interview Questions" 和 "Company Tags" 下的 "Huawei" 相关题目。
- 模拟考试:在准备后期,严格按照考试时间(2-3小时,3-4道题)进行模拟,锻炼时间分配能力和抗压能力。
- 总结复盘:对于做错的或没做出来的题,一定要分析原因:是思路错了?是边界条件没考虑到?还是代码实现有bug?把错题和经典题整理到自己的笔记中。
祝你准备顺利,在华为的校招中取得好成绩!
