赞
踩
有LeetCode算法/华为OD考试扣扣交流群可加 948025485
可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳od1336
了解算法冲刺训练
现有两组服务器A
和B
,每组有多个算力不同的CPU,其中Ai
是A
组第i
个CPU的运算能力,Bi
是B
组第i
个CPU的运算能力。一组服务器的总算力是各CPU的算力之和。
为了让两组服务器的算力相等,允许从每组各选出一个CPU进行一次交换,求两组服务器中,用于交换的CPU的算力,并且要求从A
组服务器中选出的CPU,算力尽可能小。
第一行输入为L1
和L2
,以空格分隔,L1
表示A
组服务器中的CPU数量,L2
表示B
组服务器中的CPU数量
第二行输入为A
组服务器中各个CPU的算力值,以空格分隔。
第三行输入为B
组服务器中各个CPU的算力值,以空格分隔,
1 <= L1 <= 10000
1 <= L2 <= 10000
1 <= A[i] <= 100000
1 <= B[i] <= 100000
对于每组测试数据,输出两个整数,以空格分隔,依次表示A
组选出的CPU算力、B
组选出的CPU算力,要求从A
组选出的CPU的算力尽可能小。
保证两组服务器的初始总算力不同,答案肯定存在。
2 2
1 1
2 2
1 2
3 4
1 2 3
1 2 3 4
1 3
有两种可能的选择,选择A
组中的1
和B
组中的3
进行交换,或者选择A
组中的2
和B
组中的4
进行交换,但由于要求A
组选择的算力要尽可能地小,所以选择前者。
注意有两个非常重要的条件:
第一个条件指出,只能在A
组和B
组中各挑选出1
个数据,不用考虑多组交换的情况
第二个条件指出,无需考虑不合规则的情况,必然能够找到一个A[i]
和一个B[j]
,交换后使得各自的和相等。
假设原A
组的和为sumA
,原B
组的和为sumB
,所有CPU的算力总和为sum_total
,取出的两个用于交换的元素分别为A[i]
和B[j]
。
交换后,如果A
组的和为sumA_new
,B
组的和为sumB_new
,那么一定存在以下式子成立
sumA_new = sumB_new = sum_total // 2
且sum_total
一定是一个偶数。
A`组少了一个`A[i]`多了一个`B[j]`,故变化量为`sumA_new - sumA = B[j] - A[i]
即如果交换后A
组和B
组的算力总和相等,存在式子B[j] = sumA - sumA_new + A[i]
成立。
因此,我们只需要遍历A
组中所有的元素A[i]
,然后计算对应的sumA_new - sumA + A[i]
,如果该值位于B
组中,说明B
组中可以找到对应的B[j]
。
这个步骤涉及到快速查找,因此很容易想到应该构建哈希集合setB = set(B)
。
从示例二可以得知,可以交换的组数不是唯一的。由于题目还要求从A
组服务器中选出的CPU,算力尽可能小,因此仅需把所有符合条件的A[i]
取最小值即可。
另外,由于A
组中可能出现重复元素,重复元素的计算对于本问题而言是无意义的,因此也可以构建setA = set(A)
,遍历A组元素时直接遍历setA
而非A
即可。
# 题目:【哈希集合】2023C-CPU算力分配 # 分值:100 # 作者:闭着眼睛学数理化 # 算法:哈希集合,数学 # 代码看不懂的地方,请直接在群上提问 # 输入A组的长度和B组的长度 nA, nB = map(int, input().split()) # 输入A组的情况 A = list(map(int, input().split())) # 输入B组的情况 B = list(map(int, input().split())) # 原A组的总和 sumA = sum(A) # 原B组的总和 sumB = sum(B) # 交换后A组的和,为所有元素总和的一半 sumA_new = (sumA + sumB) // 2 # 分别获得A组和B组对应的哈希集合 # setA的作用是去重,setB的作用是快速查找 setA = set(A) setB = set(B) # 找到所有满足sumA_new - sumA + Ai位于setB中的Ai的最小值,即为A组中所选的算力ansA ansA = min(Ai for Ai in setA if (sumA_new - sumA + Ai) in setB) # 对应地可以计算出ansB ansB = sumA_new - sumA + ansA # 输出答案 print(ansA, ansB)
import java.util.*; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int nA = scanner.nextInt(); int nB = scanner.nextInt(); int[] A = new int[nA]; int[] B = new int[nB]; for (int i = 0; i < nA; i++) { A[i] = scanner.nextInt(); } for (int i = 0; i < nB; i++) { B[i] = scanner.nextInt(); } int sumA = 0, sumB = 0; for (int num : A) { sumA += num; } for (int num : B) { sumB += num; } int sumANew = (sumA + sumB) / 2; Set<Integer> setB = new HashSet<>(); for (int num : B) { setB.add(num); } int ansA = Integer.MAX_VALUE; for (int num : A) { if (setB.contains(sumANew - sumA + num)) { ansA = Math.min(ansA, num); } } int ansB = sumANew - sumA + ansA; System.out.println(ansA + " " + ansB); } }
#include <iostream> #include <vector> #include <unordered_set> #include <algorithm> #include <climits> using namespace std; int main() { int nA, nB; cin >> nA >> nB; vector<int> A(nA), B(nB); for (int i = 0; i < nA; i++) { cin >> A[i]; } for (int i = 0; i < nB; i++) { cin >> B[i]; } int sumA = 0, sumB = 0; for (int num : A) { sumA += num; } for (int num : B) { sumB += num; } int sumANew = (sumA + sumB) / 2; unordered_set<int> setB(B.begin(), B.end()); int ansA = INT_MAX; for (int num : A) { if (setB.count(sumANew - sumA + num)) { ansA = min(ansA, num); } } int ansB = sumANew - sumA + ansA; cout << ansA << " " << ansB << endl; return 0; }
时间复杂度:O(N+M)
。构建两个哈希集合所需的时间复杂度
空间复杂度:O(N+M)
。两个哈希集合所占的空间。
华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务300+同学成功上岸!
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
可查看链接 大厂真题汇总 & OD真题汇总(持续更新)
绿色聊天软件戳 od1336
了解更多
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。