【华为笔试必看】华为2024届春招第一套笔试解析 | 第二题

✅ 华为备战指南 ✅

💡 学习建议:

  • 先尝试独立解题(建议用时:120分钟/套)
  • 对照解析查漏补缺
  • 配套练习题库

互联网必备刷题宝典🔗

华为笔试全解析🔗

本题库收录整理自:

  1. 互联网公开的笔试真题回忆版(经网友投稿)
  2. 各大技术社区公开讨论的经典题型
  3. 历年校招考生提供的解题思路

📢 华为技术岗笔试重要信息速览

⏰ 笔试时间安排

  • 国内场次
    🕒 每周三 19:00~21:00(连续2小时)

  • 海外场次
    🌍 周三 19:00 ~ 周四 19:00 期间任选连续2小时

  • 通知方式
    📧 考前1天通过邮箱发送考试链接与说明


🧩 笔试题型分布

岗位方向题目组成
算法岗编程题3道 ⭐
后端开发编程题+系统设计题
前端/测试编程题+场景应用题
通信算法专业综合题
自动化系统设计题

⚙️ 核心考试配置

项目配置说明
考试平台华为iLearning平台
编程模式ACM模式(需处理输入输出)
本地IDE允许使用 ✅
设备要求笔记本前置摄像头开启 ✅
考试录屏全程电脑录屏 ✅
手机管控无需小程序锁机 ❌
双机位监控不要求 ❌

🚨 考生特别注意

  1. 编程题严禁复制粘贴外部代码(系统自动查重)
  2. 中途离开考试界面超过3次将自动终止考试
  3. 海外考生需自行换算时区(建议选择网络稳定时段)
  4. 遇到技术问题可拨打考试界面客服热线(7×24小时)

🛠️ 考前自检清单

✅ 完成iLearning平台环境检测
✅ 准备身份证件(放置于摄像头可见区域)
✅ 关闭无关后台进程(微信/TeamViewer等)
✅ 确保Chrome浏览器更新至最新版
✅ 准备空白草稿纸(不超过2张)


📚 真题解析原则

  1. 所有题目均经过脱敏和题型改编
  2. 提供Java/Python/Cpp三语言实现参考
  3. 标注华为近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 1l<r100000 1 ≤ t ≤ 100000 1\le t \le 100000 1t100000

1 ≤ o p ≤ 3 1\le op \le 3 1op3 1 ≤ n u m ≤ 200 1\le num\le 200 1num200

输出描述

资源池的第一个空闲资源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();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值