华为留学生笔试 华为笔试 0508
笔试时间:2025年5月8日
往年笔试合集:
第一题:货物配送
某公司有2个仓库(用A和B表示),需要给m(m为偶数)个营业网点各配送一件货物。假设每个仓库正好都有m/2件货物,配送给不同营业网点的费用使用一个二维数组cost表示,其中cost[i]=[Ai,Bi],表示第i个营业网点从A仓发货的运费为Ai,从B仓库发货的费用为Bi。请计算m件货物配送的最低费用,要求每个营业网点都有一件货物送到。
输入描述
第一行是一个整数M,代表营业网点数量。
2<=M<=100,M为偶数第二行是一个长度为M的二维数组cost,其中cost[i]=[Ai,Bi],Ai和Bi分别表示从A、B仓库发货的费用。1<=Ai,Bi<=1000
输出描述
一个整数,表示最低费用。
样例输入
2
[[10,30],[30,200]]
样例输出
60
参考题解
本题数据范围不大,因此贪心和动态规划都可以解决。题意可以转化为,有n个二元组,要从n/2个二元组中选第一个元素,从剩下的二元组中选第二个元素,问选出的元素数值和最小是多少。贪心法:先全部假设选第一个元素,然后按差值排序,把差值小的n/2个二元组替换成B的,答案一定最小。动态规划发:dp[i][j]代表前i个二元组中有j个选了第一个元素,对dp[i+1],按照选第一个元素和选第二个元素分别从dp[i]更新过来即可。
C++:
#include <bits/stdc++.h> using namespace std; using ll = long long; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int M; cin >> M; vector<pair<ll,ll>> cost(M); for (int i = 0; i < M; i++) { cin >> cost[i].first >> cost[i].second; // cost[i].first = cost from A, cost[i].second = cost from B } // 全部从 A 仓库发货的初始总费用 ll total_cost = 0; for (int i = 0; i < M; i++) { total_cost += cost[i].first; } // 计算选择 B 仓库时比 A 仓库多花的费用差 vector<ll> diffs(M); for (int i = 0; i < M; i++) { diffs[i] = cost[i].second - cost[i].first; } // 取最小的 M/2 个差值,代表最划算切换到 B 的那些网点 sort(diffs.begin(), diffs.end()); for (int i = 0; i < M/2; i++) { total_cost += diffs[i]; } cout << total_cost << "\n"; return 0; }
Java:
// Java 版本 import java.util.Arrays; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int M = sc.nextInt(); long[][] cost = new long[M][2]; for (int i = 0; i < M; i++) { cost[i][0] = sc.nextLong(); // 从 A 仓库发货费用 cost[i][1] = sc.nextLong(); // 从 B 仓库发货费用 } sc.close(); // 全部从 A 仓库发货的初始总费用 long totalCost = 0; for (int i = 0; i < M; i++) { totalCost += cost[i][0]; } // 计算从 B 仓库多花的差值 long[] diffs = new long[M]; for (int i = 0; i < M; i++) { diffs[i] = cost[i][1] - cost[i][0]; } // 排序并取前 M/2 个最小的差值 Arrays.sort(diffs); for (int i = 0; i < M / 2; i++) { totalCost += diffs[i]; } System.out.println(totalCost); } }
Python:
def min_cost(M, cost): # 先计算全部从A仓库发货的总费用 total_cost = sum([x[0] for x in cost]) diffs = [] for i in range(M): # 计算每个营业网点从B仓库发货比从A仓库发货多花费的费用 diff = cost[i][1] - cost[i][0] diffs.append(diff) # 对费用差值进行排序 diffs.sort() # 取差值最小的M/2个,也就是从B仓库发货更划算的那些网点 for i in range(M // 2): total_cost += diffs[i] return total_cost M = int(input()) cost = eval(input()) print(min_cost(M, cost))
第二题:日志严重性能逆序列
在一家快速发展的互联网公司里,系统工程师小李正在开发一款高效的日志分析工具,旨在帮助运维团队更好地理解和优化语音合成系统的运行状况。为了提高工具的洞察力,他需要解决一个关键问题:如何通过分析一段时间内的合成请求的实时率RTF(合成耗时/目标文本的音频时长)记录来识别“性能逆序对”的总数,实时率越高代表性能越差。在这个系统中,“性能逆序对”被定义为一种情况,即如果某次请求的实时率比之后某次请求的实时率大,则这两者构成一个“性能逆序对”。这可以帮助运维团队识别出系统的性能退化点或者异当波动从而采取措施优化系统性能。具体来说,给定一个数组record,它代表了一段时间内每次请求的实时率* 100(按时间顺序排列,因正常场景实时率<1,因此对数值进行放大100并取整)。小李的任务是设计并实现一个程序,该程序能够计算并返回这段时间内存在的“性能逆序对”总数。每个“性能逆序对”由两个索引i和j组成,满足条件 0<=i<j<record.length 并且 record[i]>record[j]。如果record[i] -record[j]>threshold,则该性能逆序对称为"严重性能逆序对"。请协助小李完成这个功能的开发,确保它能高效地处理大量的日志数据,并提供即时反馈。具体任务包括编写一个函数,输入是一个整数数组 record,输出是其中存在的“严重性能逆序对”的总数。
输入描述
每组数据第一行为严重性能逆序对的阈值threshold,第二行为日志数量n,第三行为日志数据的数组record,数组数值可能重复
输出描述
严重性能逆序对的总数
样例输入
2
5
9 7 5 4 6
样例输出
4
解释:输入:record=[9,7,5,4,6],threshold=2 输出:4 解释:日志中的严重性能逆序对为(9,5),(9,4),(9,6),(7,4),这些逆序对满足序对第一个值大于第二个且差值大于2
参考题解
逆序对的变种,需要差值达到阈值threshold才能被统计进答案。常见的O(nlogn)逆序对做法有归并排序或树状数组,这里对逆序对的变种,使用树状数组的解法更简单。
C++:
#include <bits/stdc++.h> using namespace std; using ll = long long; struct BinaryIndexedTree { int n; vector<ll> bit; BinaryIndexedTree(int _n) : n(_n), bit(n+1, 0) {} // 在位置 idx 增加 val void update(int idx, ll val) { for (; idx <= n; idx += idx & -idx) { bit[idx] += val; } } // 查询前缀和 [1..idx] ll query(int idx) const { ll res = 0; for (; idx > 0; idx -= idx & -idx) { res += bit[idx]; } return res; } }; ll solve(const vector<int>& record, int threshold) { int max_val = *max_element(record.begin(), record.end()); BinaryIndexedTree bit(max_val); ll count = 0; // 从后向前遍历 for (auto it = record.rbegin(); it != record.rend(); ++it) { int num = *it; int target = num - threshold - 1; if (target > 0) { count += bit.query(target); } bit.update(num, 1); } return count; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int threshold, n; cin >> threshold >> n; vector<int> record(n); for (int i = 0; i < n; i++) { cin >> record[i]; } cout << solve(record, threshold) << "\n"; return 0; }
Java:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.util.StringTokenizer; public class Main { static class BinaryIndexedTree { private final int n; private final long[] bit; public BinaryIndexedTree(int n) { this.n = n; this.bit = new long[n+1]; } // 在 idx 位置增加 val public void update(int idx, long val) { for (; idx <= n; idx += idx & -idx) { bit[idx] += val; } } // 查询前缀和 [1..idx] public long query(int idx) { long res = 0; for (; idx > 0; idx -= idx & -idx) { res += bit[idx]; } return res; } } static long solve(int[] record, int threshold) { int maxVal = 0; for (int v : record) { if (v > maxVal) maxVal = v; } BinaryIndexedTree bit = new BinaryIndexedTree(maxVal); long count = 0; // 从后往前遍历 for (int i = record.length - 1
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南