华为笔试 华为笔试题 0514
笔试时间:2025年5月14日
往年笔试合集:
第一题:AI算法训练中的动态优先级经验回放
AI算力资源宝贵,在AI算法训练中,经验回放机制通过存储和重用过去的经验数据来提高算法训练效率,以节省算力资源和提升迭代速度。为了进一步优化,我们使用优先级经验回放,根据每个经验的TD误差(Temporal Difference Error)动态调整其采样优先级。请设计一个高效的数据结构和算法,支持以下操作:插入经验:将新经验加入经验池,并赋予初始优先级。提取Top K经验:取出优先级最高的K个经验(按优先级降序排列,若优先级相同则按id升序排列)。提取后,池中减少已提取的经验。若池中剩余经验数小于K,返回-1。更新优先级:根据训练后的TD误差,更新指定经验的优先级。每次更新后,之前提取的经验重新回到池中,且优先级为最新值。给定N个按时间顺序发生的操作(插入/提取/更新),请输出每次提取操作的结果。
输入描述
第一行为整数N,表示操作总数。接下来N行,每行表示一个操作:+id score:插入ID为id的经验,初始优先级为score。= id newScore:将ID为id的经验的优先级更新为newScore。-k:提取当前优先级最高的k个经验id。约束条件:
1 ≤ N ≤ 1e5
1 ≤ id ≤ 1e5(保证同一id不会被重复插入)
0 < score, newScore ≤ 1e9
1 ≤ k ≤ 10001
输出描述
对每个extract操作,按顺序输出提取的id列表(空格分隔)。若有多次extract操作的输出,则后面的extract操作在前一次输出结果之后换行输出。
若extract返回-1,输出-1。
若所有操作记录中没有extract操作,则返回nuIl。
若入参的操作总数N和实际的操作行数不匹配,则返回null
样例输入
7
+ 1 5
+ 2 10
+ 3 7
- 2
= 3 20
- 1
- 1
样例输出
2 3
3
2
解释:
初始池:[(1,5), (2,10), (3,7)]
提取Top2:优先级最高的为2(10)和3(7),输出2 3,池剩余[(1,5)]。
更新id=3的优先级为20后,池变为[(1,5), (2,10), (3,20)](之前提取的经验重新加入)。
提取Top1:优先级最高为3(20),输出3,池剩余[(1,5), (2,10)]。
再次提取Top1:优先级最高为2(10),输出2。
参考题解
模拟
C++:
#include <iostream>
#include <set>
#include <vector>
#include <string>
usingnamespacestd;
int main() {
int n;
cin >> n;
set<pair<int, int>, greater<pair<int, int> > > experienceSet, allSet;
unordered_map<int, pair<int, int> > idToPair;
for (int i = 0; i < n; ++i) {
string op;
cin >> op;
if (op == "+") {
int id, score;
cin >> id >> score;
// 检查是否已存在该 id
if (idToPair.find(id) != idToPair.end()) {
continue; // 忽略已存在的 id
}
// 插入新元素
auto p = make_pair(score, id);
experienceSet.insert(p);
allSet.insert(p);
idToPair[id] = p;
} elseif (op == "=") {
int id, newScore;
cin >> id >> newScore;
// 检查是否存在该 id
if (idToPair.find(id) == idToPair.end()) {
continue; // 忽略不存在的 id
}
experienceSet = allSet; // 重置 set,使得 set 按 score 降序、id 升序排列
// 从 set 中删除旧的 pair
auto oldPair = idToPair[id];
experienceSet.erase(oldPair);
// 插入新的 pair
auto newPair = make_pair(newScore, id);
experienceSet.insert(newPair);
idToPair[id] = newPair;
} elseif (op == "-") {
int k;
cin >> k;
// 检查是否有足够的元素
if (experienceSet.size() < k) {
cout << -1 << endl;
continue;
}
vector<int> result;
auto it = experienceSet.begin();
for (int i = 0; i < k; ++i) {
result.push_back(it->second); // 提取 id
++it;
}
for (int i = 0; i < result.size(); ++i) {
cout << result[i] << (i == result.size() - 1 ? '\n' : ' ');
auto oldPair = idToPair[result[i]];
experienceSet.erase(oldPair);
}
}
}
return0;
}
Java:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.*;
public class Main {
static class Pair {
int score, id;
Pair(int score, int id) {
this.score = score;
this.id = id;
}
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
// 按 score 降序,id 升序
Comparator<Pair> comp = (a, b) -> {
if (a.score != b.score) return Integer.compare(b.score, a.score);
return Integer.compare(a.id, b.id);
};
TreeSet<Pair> experienceSet = new TreeSet<>(comp);
TreeSet<Pair> allSet = new TreeSet<>(comp);
Map<Integer, Pair> idToPair = new HashMap<>();
for (int i = 0; i < n; i++) {
String[] parts = br.readLine().split("\\s+");
String op = parts[0];
if (op.equals("+")) {
int id = Integer.parseInt(parts[1]);
int score = Integer.parseInt(parts[2]);
if (idToPair.containsKey(id)) continue;
Pair p = new Pair(score, id);
experienceSet.add(p);
allSet.add(p);
idToPair.put(id, p);
} else if (op.equals("=")) {
int id = Integer.parseInt(parts[1]);
int newScore = Integer.parseInt(parts[2]);
if (!idToPair.containsKey(id)) continue;
// 重置 experienceSet
experienceSet = new TreeSet<>(allSet);
// 替换旧的
Pair oldP = idToPair.get(id);
experienceSet.remove(oldP);
Pair newP = new Pair(newScore, id);
experienceSet.add(newP);
// 更新映射(注意:allSet 保持不变以供下次重置)
idToPair.put(id, newP);
} else if (op.equals("-")) {
int k = Integer.parseInt(parts[1]);
if (experienceSet.size() < k) {
System.out.println(-1);
continue;
}
Iterator<Pair> it = experienceSet.iterator();
StringBuilder sb = new StringBuilder();
for (int cnt = 0; cnt < k; cnt++) {
Pair p = it.next();
sb.append(p.id).append(cnt == k - 1 ? "\n" : " ");
it.remove();
}
System.out.print(sb);
}
}
}
}
Python:
import sys
import bisect
def insert_sorted(lst, pair):
# pair = ( -score, id )
bisect.insort(lst, pair)
def remove_pair(lst, pair):
# locate and remove one instance
i = bisect.bisect_left(lst, pair)
if i < len(lst) and lst[i] == pair:
lst.pop(i)
def main():
input_data = sys.stdin.read().split()
it = iter(input_data)
n = int(next(it))
# 存储 ( -score, id ),这样默认升序即 score 降序、id 升序
experience = []
all_list = []
id_to_pair = {}
for _ in range(n):
op = next(it)
if op == "+":
id_ = int(next(it))
score = int(next(it))
if id_ in id_to_pair:
continue
pair = (-score, id_)
insert_sorted(experience, pair)
insert_sorted(all_list, pair)
id_to_pair[id_] = pair
elif op == "=":
id_ = int(next(it))
new_score = int(next(it))
if id_ not in id_to_pair:
continue
# 重置 experience
experience = all_list.copy()
old_pair = id_to_pair[id_]
remove_pair(experience, old_pair)
new_pair = (-new_score, id_)
insert_sorted(experience, new_pair)
id_to_pair[id_] = new_pair
# all_list 不变,用于下次重置
elif op == "-":
k = int(next(it))
if len(experience) < k:
print(-1)
continue
res = []
for _ in range(k):
pair = experience.pop(0)
res.append(str(pair[1]))
print(" ".join(res))
if __name__ == "__main__":
main()
第二题:游戏中的地图穿越
小明用 k*k 的二维矩阵 map 表示三维空间中的一个地图,map[i][j] 表示位置 [i][j] 的地形高度。玩家需控制角色从矩阵左上角 [0,0] 进入,从矩阵右侧任意位置(即第 k-1 列的任意行)出去。1.角色只能向右或向下移动。2.相邻两节点高度差绝对值若大于 1,角色无法移动(太高爬不上去,太低会摔死)。3.角色经过 [i][j] 时,消耗 map[i][j] 点体力值。 求最省体力值的路线所消耗的体力值总和。若无可行路径或参数不合法,返回特定结果。
输入描述
输入有多行,第1行为数组的行数k(k<=100),第2行至第k+1行为k*k矩阵,数组元素用空格分隔,,且 0 ≤ map
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南
查看1道真题和解析
