乐于分享
好东西不私藏

华为非AI方向实习机考 | 6月3日最新笔试题与解析

华为非AI方向实习机考 | 6月3日最新笔试题与解析

写在前面

本次给大家带来2026年6月3日华为非AI方向笔试题的3道题,涉及到的岗位是:通软,嵌软,测试,普通算法(岗位名中不包含AI)以及数据科学,和报考部门无关,统一考本套卷子。

我整理的考试题单+攻略可访问文章底部左侧:阅读原文

第一题:先按冒号把字符串分成  组,扫描找出最长的、由相同且组内字符也全相同的连续数字组用 ** 压缩,再对剩余组去除前导  并拼接输出。

第二题:枚举每个节点作为炸弹放置点,用  统计距离不超过  的所有节点收益之和,最后取最大值。

第三题:把任务依赖看成拓扑约束,回溯枚举所有可执行任务的调度顺序,每次按所需卡的最早空闲时间和依赖完成时间计算任务最早结束时间,取所有方案中的最小总耗时。

塔子哥的配套刷题网站:codefun2000.com

题号
题目
难度(对标leetcode)
核心做法
1
数字标识符压缩算法
中等
模拟
2
爆破小游戏
中等
DFS
3
昇腾NPU协同调度系统
困难
DFS

第1题-数字标识符压缩算法

题目内容

标准的数字标识符由  位组成,通常表示为  组  位小写十六进制数,每组之间用冒号 () 分隔。例如:

为了提高可读性,需要对数字标识符进行压缩。

压缩规则

规则1:前导零压缩

每组  位小写十六进制数,前导的零可以省略 例如:

规则2:连续相同数字组压缩

连续的相同数字组(即所有位都是同一个数字,如 等)可以用双冒号  表示,但只能使用一次

例如:

注意:如果有多个连续相同数字组,只能压缩最长的一组;如果长度相同,压缩左边的那一组

规则3:压缩优先级

首先应用规则 (连续相同数字组压缩),然后应用规则 (前导零压缩)

例如:,即先合并后压缩前导零

输入描述

  • 一个字符串 ,表示数字标识符
  • 输入保证是完整且有效的标准数字标识符( 组,每组  位小写十六进制字符)
  • 字符串长度固定为 

输出描述

压缩后的数字标识符字符串

示例

输入
输出
2001:0db8:85a3:0010:0001:8a2e:0370:7334
2001:db8:85a3:10:1:8a2e:370:7334
1111:2222:2222:3333:4444:5555:6666:7777
1111:**:3333:4444:5555:6666:7777
0001:0002:0003:0004:0005:0006:0007:0008
1:2:3:4:5:6:7:8
2222:2222:aaaa:bbbb:2222:2222:cccc:dddd
::aaaa:bbbb:2222:2222:cccc:dddd
2001:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:2222
2001::2222

样例1

输入

2001:0db8:85a3:0010:0001:8a2e:0370:7334

输出

2001:db8:85a3:10:1:8a2e:370:7334

说明

只应用规则 ,因为没有相同数字组

样例2

输入

1111:2222:2222:3333:4444:5555:6666:7777

输出

1111:**:3333:4444:5555:6666:7777

说明

压缩最长的连续相同数字组()

题解

解题思路

使用字符串模拟和最长连续段扫描。

将输入按冒号切成  个字符串组。压缩时先执行规则 ,再执行规则 

可被 ** 压缩的候选段需要满足:

该段由若干个连续相同的组组成,并且这个组本身  位字符完全相同,例如 

从左到右扫描所有组,找到最长的候选段。如果长度相同,只保留最左边的一段。候选段长度可以为 ,只要该组本身符合条件即可。

之后重新构造答案:

遇到最长候选段的起点时,加入 **,并跳过整段。

其他普通组去掉前导 ,如果去完为空,则变成 

最后用冒号拼接即可。

复杂度分析

因为题目固定为  个组,每组长度为 ,所以时间复杂度为 ,空间复杂度为 

如果按通用形式分析,设有  个组,每组长度为 ,时间复杂度为 ,空间复杂度为 

代码实现

python代码(C++和JAVA代码见在线OJ网址)

import sysdefis_same_digit_group(s):# 判断一个组的4位字符是否完全相同return s[0] == s[1] == s[2] == s[3]defremove_leading_zero(s):# 去除前导0,如果全部是0,则返回"0"    i = 0while i < len(s) and s[i] == '0':        i += 1if i == len(s):return"0"return s[i:]defcompress_identifier(s):    groups = s.split(':')    best_start = -1    best_len = 0    i = 0# 先寻找可以用**压缩的最长连续相同数字组while i < 8:if is_same_digit_group(groups[i]):            j = i + 1while j < 8and groups[j] == groups[i]:                j += 1            length = j - i# 只在更长时更新,长度相同自动保留左边if length > best_len:                best_len = length                best_start = i            i = jelse:            i += 1    ans = []    i = 0# 构造最终结果while i < 8:if i == best_start:            ans.append("**")            i += best_lenelse:            ans.append(remove_leading_zero(groups[i]))            i += 1return":".join(ans)defmain():    data = sys.stdin.read().strip().split()ifnot data:return    s = data[0]    print(compress_identifier(s))if __name__ == "__main__":    main()

第2题-爆破小游戏

题目内容

云小核正在玩爆破小游戏,游戏提供了一张地图,可以看成一棵树,地图上有很多节点,每个节点都有被爆破后的收益值,有些节点之间有边和距离。云小核手中有一颗炸弹,可以放置在任意一个节点上。这颗炸弹标定了影响范围,只要和放置炸弹节点的距离(路径上边的和)小于等于影响范围的节点,都会被爆破,云小核获得的收益值是所有被爆破节点收益值的总和。请你帮云小核选择一个炸弹放置点,使得云小核获得的收益最大。

如下图所示,当炸弹放置在节点或节点时,获得收益最大,为 

输入描述

  • 第  行:两个整型数值, 和  表示节点数量, 表示炸弹影响范围
  • 第  行: 个整型数值,,表示每个节点对应的收益
  • 接下来  行:三个整型数值,,表示节点和节点之间有条边,距离为 

输出描述

一个整型数值,表示获得的最大收益

样例1

输入

7 310 10 10 300 10 10 3000 1 10 2 11 3 31 4 12 5 32 6 1

输出

640

说明

样例2

输入

5 2200 100 250 100 1001 0 200 2 203 1 24 1 2

输出

300

说明

题解

解题思路

本题是一棵带边权的树,有  个节点,每个节点有收益 ,炸弹影响范围为 

如果炸弹放在节点 ,那么所有到  的路径距离不超过  的节点都会被摧毁,收益为这些节点收益之和。

由于树上任意两个节点之间路径唯一,可以枚举每个节点作为炸弹放置点,然后从该节点开始做一次 ,统计距离不超过  的所有节点收益。

核心步骤:

  1. 建图,保存每条边的终点和距离。
  2. 枚举每个节点  作为炸弹放置点。
  3. 从  开始 ,累计当前距离 
  4. 如果 ,加入该节点收益;否则停止继续搜索。
  5. 取所有放置点收益的最大值。

使用的算法是树上深度优先搜索 

复杂度分析

设节点数为 

每个节点都作为起点做一次 ,一次  最多访问  个节点。

时间复杂度为 

邻接表存树,空间复杂度为 

由于 ,该复杂度完全可以通过。

代码实现

python代码(C++和JAVA代码见在线OJ网址)

import sysdefdfs(u, parent, dist, k, values, graph):# 超出影响范围,不再继续搜索if dist > k:return0# 当前节点被摧毁,加入收益    total = values[u]# 继续搜索相邻节点for v, w in graph[u]:if v != parent:            total += dfs(v, u, dist + w, k, values, graph)return totaldefsolve(n, k, values, graph):    ans = 0# 枚举每个节点作为炸弹放置点for i in range(n):        cur = dfs(i, -10, k, values, graph)        ans = max(ans, cur)return ansdefmain():    data = list(map(int, sys.stdin.read().split()))    idx = 0    n = data[idx]    k = data[idx + 1]    idx += 2    values = data[idx:idx + n]    idx += n    graph = [[] for _ in range(n)]for _ in range(n - 1):        u = data[idx]        v = data[idx + 1]        w = data[idx + 2]        idx += 3# 无向树,双向建边        graph[u].append((v, w))        graph[v].append((u, w))    print(solve(n, k, values, graph))if __name__ == "__main__":    main()

第3题-昇腾NPU协同调度系统

题目内容

设计一个调度系统管理昇腾  上的训练任务,需满足以下条件:

任务属性(每个任务包含个维度)

  1. :所需  卡编号列表
  2. :执行需要的时间片数
  3. :必须在该任务前完成的任务 (只会依赖  或者  个上游任务)

调度规则

  1. 每张  卡同一时间只能执行一个任务
  2. 任务必须在前置任务完成后才能开始
  3. 时间片为正整数,多个满足条件的任务可并行启动,不可抢占已分配任务
  4. 可能存在多种调度方案,需要选出全部任务结束耗时最短的一种

用例保证存在可调度方案(不存在任务间循环依赖),输出所有任务全部完成需要的最短时间。

输入描述

第  行, 卡总数(),总任务数量(),如:

第  行,【第  行第  个任务】,任务  依赖的  列表(空格分割),如:

第  行,【第  行第  个任务】,任务  持续时间,如:

第  行,【第  行第  个任务】,任务  依赖的上游任务 (无依赖时固定为 ),如:

第  行,【第  行第  个任务】,任务  依赖的  列表(空格分割),如:

第  行,【第  行第  个任务】,任务  持续时间,如:

第  行,【第  行第  个任务】,任务  依赖的上游任务 (无依赖时固定为 ),如:

……,如果存在更多任务, 行一组进行输入,任务  依赖的  列表(空格分割),如:

……,如果存在更多任务, 行一组进行输入,任务  持续时间,如:

……,如果存在更多任务, 行一组进行输入,任务  依赖的上游任务 (无依赖时固定为 ),如:

注意:题目保证输入合法,无需校验输入

输出描述

格式: 类型数值

解释:所有任务全部完成需要的最短时间,用例保证存在可调度方案(不存在任务间循环依赖)

样例1

输入

2 303-102-1141

输出

6

说明

  •  # 个NPU卡,个任务
  •  # 任务需要NPU卡
  •  # 任务持续
  •  # 任务无依赖
  •  # 任务需要NPU卡
  •  # 任务持续
  •  # 任务无依赖
  •  # 任务需要NPU卡
  •  # 任务持续
  •  # 任务依赖任务

方案1:优先执行耗时长的任务(任务先执行)

  • 时间~NPU: 任务(持续,时间-) NPU: 空闲(任务依赖任务,还未完成)

  • 时间~NPU: 任务(持续,时间-) NPU: 空闲(任务需等待任务,任务在时间完成,但任务还未开始)

  • 时间~NPU: 空闲 NPU: 任务(持续,时间-

任务完成时间:任务: 时间完成 任务: 时间完成 任务: 时间完成

总时间:

方案2:优先执行耗时短的任务(任务先执行)

  • 时间~NPU: 任务(持续,时间-) NPU: 空闲(任务依赖任务,还未完成)

  • 时间~NPU: 任务(持续,时间-) NPU: 任务(持续,时间-,任务在时间已完成,满足依赖)

  • 时间~NPU: 空闲(任务已完成) NPU: 任务继续执行(时间-

任务完成时间:

任务: 时间完成 任务: 时间完成 任务: 时间完成

总时间:

样例2

输入

3 20 14-11 250

输出

9

说明

  •  # 个NPU卡,个任务
  •  # 任务需要NPU卡、卡
  •  # 任务持续
  •  # 任务无依赖
  •  # 任务需要NPU卡、卡
  •  # 任务持续
  •  # 任务依赖任务

调度顺序: 任务依赖任务,只能先执行任务再执行任务,总耗时,输出

提示 编号从  开始,任务编号从  开始

题解

解题思路

任务数量较小,可以使用回溯枚举所有满足依赖关系的任务执行顺序。

核心算法是拓扑顺序枚举 + 最早可行时间调度:

每个任务用一个二进制状态表示所需的卡集合。

在回溯过程中维护:

:已经安排过的任务集合。

:任务的完成时间。

:第卡最早可用时间。

每次选择一个未安排且依赖任务已经完成的任务,计算它的最早开始时间:

然后得到:

更新相关卡的可用时间,继续搜索。用当前已知答案做剪枝,如果当前时间已经不可能更优,就停止搜索。

复杂度分析

设任务数量为卡数量为

最坏情况下需要枚举所有任务顺序,时间复杂度为

递归深度为,需要维护可用时间和任务完成时间,空间复杂度为

由于题目中较小,该复杂度可以通过。

代码实现

python代码(C++和JAVA代码见在线OJ网址)

defsolve(card_cnt, task_cnt, need, duration, pre):    ans = [10 ** 18]    free = [0] * card_cnt    finish = [0] * task_cntdefdfs(done, cur_time):# 如果所有任务都已安排,更新答案if done == (1 << task_cnt) - 1:            ans[0] = min(ans[0], cur_time)return# 当前时间已经不优,直接剪枝if cur_time >= ans[0]:returnfor i in range(task_cnt):if done & (1 << i):continue# 依赖任务未完成,不能执行if pre[i] != -1andnot (done & (1 << pre[i])):continue            start = 0if pre[i] != -1:                start = finish[pre[i]]# 任务需要的所有NPU卡都必须空闲for c in range(card_cnt):if need[i] & (1 << c):                    start = max(start, free[c])            end = start + duration[i]            new_time = max(cur_time, end)if new_time >= ans[0]:continue            old_free = free[:]            old_finish = finish[i]# 占用对应NPU卡for c in range(card_cnt):if need[i] & (1 << c):                    free[c] = end            finish[i] = end            dfs(done | (1 << i), new_time)# 回溯恢复现场            free[:] = old_free            finish[i] = old_finish    dfs(00)return ans[0]defmain():    card_cnt, task_cnt = map(int, input().split())    need = []    duration = []    pre = []for _ in range(task_cnt):        nums = list(map(int, input().split()))        mask = 0for x in nums:            mask |= 1 << x        need.append(mask)        duration.append(int(input()))        pre.append(int(input()))    print(solve(card_cnt, task_cnt, need, duration, pre))if __name__ == "__main__":    main()