✅ 华为备战指南 ✅
💡 学习建议:
- 先尝试独立解题(建议用时:120分钟/套)
- 对照解析查漏补缺
- 配套练习题库
互联网必备刷题宝典🔗
华为笔试全解析🔗
本题库收录整理自:
- 互联网公开的笔试真题回忆版(经网友投稿)
- 各大技术社区公开讨论的经典题型
- 历年校招考生提供的解题思路
📢 华为技术岗笔试重要信息速览
⏰ 笔试时间安排
-
国内场次:
🕒 每周三 19:00~21:00(连续2小时) -
海外场次:
🌍 周三 19:00 ~ 周四 19:00 期间任选连续2小时 -
通知方式:
📧 考前1天通过邮箱发送考试链接与说明
🧩 笔试题型分布
岗位方向 | 题目组成 |
---|---|
算法岗 | 编程题3道 ⭐ |
后端开发 | 编程题+系统设计题 |
前端/测试 | 编程题+场景应用题 |
通信算法 | 专业综合题 |
自动化 | 系统设计题 |
⚙️ 核心考试配置
项目 | 配置说明 |
---|---|
考试平台 | 华为iLearning平台 |
编程模式 | ACM模式(需处理输入输出) |
本地IDE | 允许使用 ✅ |
设备要求 | 笔记本前置摄像头开启 ✅ |
考试录屏 | 全程电脑录屏 ✅ |
手机管控 | 无需小程序锁机 ❌ |
双机位监控 | 不要求 ❌ |
🚨 考生特别注意
- 编程题严禁复制粘贴外部代码(系统自动查重)
- 中途离开考试界面超过3次将自动终止考试
- 海外考生需自行换算时区(建议选择网络稳定时段)
- 遇到技术问题可拨打考试界面客服热线(7×24小时)
🛠️ 考前自检清单
✅ 完成iLearning平台环境检测
✅ 准备身份证件(放置于摄像头可见区域)
✅ 关闭无关后台进程(微信/TeamViewer等)
✅ 确保Chrome浏览器更新至最新版
✅ 准备空白草稿纸(不超过2张)
📚 真题解析原则
- 所有题目均经过脱敏和题型改编
- 提供Java/Python/Cpp三语言实现参考
- 标注华为近3年真题考点分布
(更多备考资料请登录iLearning查看官方指引)
题目二:资源池管理
题目内容
你是一名网络工程师,你正在为一家云计算公司开发一个虚拟机管理系统。你的系统需要为每个虚拟机分配一个唯一的ID,用来标识和通信。为了实现这个功能,你设计了一个管理ID的资源池,可以从资源池中分配资源ID和释放资源ID,分配方式有动态分配和指定分配。
动态分配是从资源池的开始分配一个资源ID,这种方式适用于新创建的虚拟机。指定分配是指定一个资源ID进行分配,这种方式适用于恢复或迁移的虚拟机。无论哪种分配方式释放资源ID时都需要放到资源池的尾部,这样可以保证资源ID的重用和均衡。
现在,你已经执行了一系列操作,你需要知道资源池的第一个空闲资源ID应该是多少,以便为下一个虚拟机分配。
注意:
资源池的初始顺序是从小到大。
资源池中空闲资源ID不足时,动态分配失败,对资源池不进行任何操作。指定分配资源ID已经被占用或者不在资源池范围内时,对资源池不进行任何操作。
释放资源ID不在资源池范围内时或者已经是空闲资源ID时,对资源池不进行任何操作。
保证每个用例最后都有空闲资源ID。
输入描述
输入第一行为两个整数 l l l 和 r r r ,表示资源池的范围;
输入第二行为一个整数 t t t ,表示操作个数。
第三行开始,第一个数字代表操作类型 o p op op , 1 1 1 表示动态分配, 2 2 2 表示指定分配, 3 3 3 表示释放;
如果输入的第一个数字是 1 1 1 ,第二个表示分配的个数 n u m num num ;
如果输入的第一个数字是 2 2 2 ,第二个表示分配的资源ID;
如果输入的第一个数字是 3 3 3 ,第二个表示释放的资源ID。
1 ≤ l < r ≤ 100000 1\le l\lt r \le 100000 1≤l<r≤100000 , 1 ≤ t ≤ 100000 1\le t \le 100000 1≤t≤100000 ;
1 ≤ o p ≤ 3 1\le op \le 3 1≤op≤3 , 1 ≤ n u m ≤ 200 1\le num\le 200 1≤num≤200 。
输出描述
资源池的第一个空闲资源ID。
样例1
输入
1 3
2
1 1
3 1
输出
2
样例解释
第一行资源池范围是 [ 1 , 3 ] [1,3] [1,3] ,资源池的初始顺序是 1 − > 2 − > 3 1->2->3 1−>2−>3 。
第二行操作个数有 2 2 2 个。
第三行动态分配 1 1 1 个资源ID,资源池中剩余的资源ID顺序是 2 − > 3 2->3 2−>3 。
第四行释放 1 1 1 个资源ID、资源ID是 1 1 1 ,资源池中剩余的资源ID顺序是 2 − > 3 − > 1 2->3->1 2−>3−>1 。
执行以上操作后,资源池的第一个空闲资源ID是 2 2 2 。
样例2
输入
1 3
3
2 2
3 2
1 1
输出
3
样例解释
第一行资源池范围是 [ 1 , 3 ] [1,3] [1,3] ,资源池的初始顺序是 1 − > 2 − > 3 1->2->3 1−>2−>3 。
第二行操作个数有 3 3 3 个。
第三行指定分配 1 1 1 个资源ID,资源ID是 2 2 2 ,资源池中剩余的资源ID顺序是 1 − > 3 − > 2 1->3->2 1−>3−>2 。
第四行释放 1 1 1 个资源ID,资源ID是 2 2 2 ,资源池中剩余的资源ID顺序是 1 − > 3 − > 2 1->3->2 1−>3−>2 。
第五行动态分配 1 1 1 个资源ID,分配的资源ID是 1 1 1 ,资源池中剩余的资源D顺序是 3 − > 2 3->2 3−>2 。
执行以上操作后,资源池的第一个空闲资源ID是 3 3 3 。
题解
数组模拟双向链表
思路步骤
1.初始化资源池:
给定资源池的范围 [l, r],我们需要用两个数组分别表示每个资源ID的左邻居和右邻居,同时还需要一个数组表示某个资源ID是否被占用。
2.动态分配资源ID:
根据要求,动态分配会从资源池的开始位置,按顺序分配指定数量的ID。每次分配一个ID后,我们将其从可用资源链表中移除,并更新链表的头部指针。
3.指定分配资源ID:
如果指定分配的ID在资源池范围内且未被占用,则将其从可用链表中移除。如果该ID正好是资源池的头或尾,还需要特别处理。
4.释放资源ID:
释放的资源ID需要重新加入到资源池的尾部,同时恢复它与前后节点的连接。
5.操作执行后:
每次操作结束后,输出资源池中第一个空闲的资源ID。
三语言参考代码
Cpp
#include <iostream>
using namespace std;
const int N = 100010;
int l_ptr, r_ptr;
int n;
int left_node[N], right_node[N]; // 每个节点的左右邻居
int used[N]; // 节点是否已使用
int free_cnt, head_ptr, tail_ptr; // 剩余节点数量,头尾指针
int main() {
cin >> l_ptr >> r_ptr;
// 建立链表关系
for(int i = l_ptr; i <= r_ptr; i++) {
left_node[i] = i-1;
right_node[i] = i+1;
}
cin >> n;
head_ptr = l_ptr;
tail_ptr = r_ptr;
free_cnt = r_ptr - l_ptr + 1;
for(int i = 0; i < n; i++) {
int op_type, val;
cin >> op_type >> val;
if(op_type == 1) {
if(free_cnt < val) continue;
while(val--) {
right_node[left_node[head_ptr]] = right_node[head_ptr];
left_node[right_node[head_ptr]] = left_node[head_ptr];
used[head_ptr] = 1;
free_cnt--;
head_ptr = right_node[head_ptr];
}
} else if(op_type == 2) {
if(val < l_ptr || val > r_ptr || used[val]) continue;
right_node[left_node[val]] = right_node[val];
left_node[right_node[val]] = left_node[val];
if(val == head_ptr) head_ptr = right_node[val];
else if(val == tail_ptr) tail_ptr = left_node[val];
used[val] = 1;
free_cnt--;
} else {
if(val < l_ptr || val > r_ptr || !used[val]) continue;
if(free_cnt == 0) {
head_ptr = tail_ptr = val;
} else {
right_node[tail_ptr] = val;
left_node[val] = tail_ptr;
tail_ptr = val;
}
used[val] = 0;
free_cnt++;
}
}
cout << head_ptr << endl;
return 0;
}
Python
class Node:
def __init__(self, id_val=None):
self.prev = None
self.next = None
self.id_val = id_val
head = Node() # 头部存储最近没使用过的节点
tail = Node() # 尾部存储最近刚使用过的节点
head.next = tail
tail.prev = head
id_map = {}
def add_to_tail(node: Node):
global tail
tail.prev.next = node
node.prev = tail.prev
node.next = tail
tail.prev = node
def remove_node(node: Node):
node.prev.next = node.next
node.next.prev = node.prev
def main():
range_start, range_end = map(int, input().split())
for id_val in range(range_start, range_end + 1):
node = Node(id_val)
id_map[id_val] = node
add_to_tail(node)
op_count = int(input())
for _ in range(op_count):
op = list(map(int, input().split()))
if op[0] == 1: # 动态分配
count = op[1]
if count > len(id_map):
continue
node = head.next
while node and node.id_val and count > 0:
remove_node(node)
del id_map[node.id_val]
count -= 1
node = node.next
elif op[0] == 2: # 指定分配
target_id = op[1]
if target_id in id_map:
node = id_map[target_id]
remove_node(node)
del id_map[node.id_val]
elif op[0] == 3: # 释放
free_id = op[1]
if free_id not in id_map:
node = Node(free_id)
add_to_tail(node)
id_map[free_id] = node
print(head.next.id_val)
if __name__ == "__main__":
main()
Java
import java.util.*;
public class Main {
static class ListNode {
int idVal;
ListNode prev;
ListNode next;
ListNode(int val) {
this.idVal = val;
}
}
static ListNode dummyHead = new ListNode(0);
static ListNode dummyTail = new ListNode(0);
static Map<Integer, ListNode> idToNode = new HashMap<>();
static void addToTail(ListNode node) {
ListNode lastNode = dummyTail.prev;
lastNode.next = node;
node.prev = lastNode;
node.next = dummyTail;
dummyTail.prev = node;
}
static void removeNode(ListNode node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int rangeStart = scan.nextInt();
int rangeEnd = scan.nextInt();
dummyHead.next = dummyTail;
dummyTail.prev = dummyHead;
for (int id = rangeStart; id <= rangeEnd; id++) {
ListNode node = new ListNode(id);
idToNode.put(id, node);
addToTail(node);
}
int opCount = scan.nextInt();
for (int i = 0; i < opCount; i++) {
int opType = scan.nextInt();
int val = scan.nextInt();
if (opType == 1) { // 动态分配
if (val > idToNode.size()) continue;
ListNode curr = dummyHead.next;
while (curr != dummyTail && val > 0) {
ListNode next = curr.next;
removeNode(curr);
idToNode.remove(curr.idVal);
val--;
curr = next;
}
} else if (opType == 2) { // 指定分配
ListNode node = idToNode.get(val);
if (node != null) {
removeNode(node);
idToNode.remove(val);
}
} else { // 释放
if (!idToNode.containsKey(val) && val >= rangeStart && val <= rangeEnd) {
ListNode node = new ListNode(val);
addToTail(node);
idToNode.put(val, node);
}
}
}
System.out.println(dummyHead.next.idVal);
scan.close();
}
}