华为笔试 华为笔试题 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等多种语言做法集合指南