本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、题目描述:
爱丽丝和鲍勃拥有不同总数量的糖果。给你两个数组 aliceSizes 和 bobSizes ,aliceSizes[i] 是爱丽丝拥有的第 i 盒糖果中的糖果数量,bobSizes[j] 是鲍勃拥有的第 j 盒糖果中的糖果数量。
两人想要互相交换一盒糖果,这样在交换之后,他们就可以拥有相同总数量的糖果。一个人拥有的糖果总数量是他们每盒糖果数量的总和。
返回一个整数数组 answer,其中 answer[0] 是爱丽丝必须交换的糖果盒中的糖果的数目,answer[1] 是鲍勃必须交换的糖果盒中的糖果的数目。如果存在多个答案,你可以返回其中 任何一个 。题目测试用例保证存在与输入对应的答案。
示例 1:
输入:aliceSizes = [1,1], bobSizes = [2,2]
输出:[1,2]
示例 2:
输入:aliceSizes = [1,2], bobSizes = [2,3]
输出:[1,2]
示例 3:
输入:aliceSizes = [2], bobSizes = [1,3]
输出:[2,3]
示例 4:
输入:aliceSizes = [1,2,5], bobSizes = [2,4]
输出:[5,4]
提示:
- 1 <= aliceSizes.length, bobSizes.length <= 10^4
- 1 <= aliceSizes[i], bobSizes[j] <= 10^5
- 爱丽丝和鲍勃的糖果总数量不同。
- 题目数据保证对于给定的输入至少存在一个有效答案。
二、思路分析:
先分别求出Alice 和 Bob 手里糖果棒的总量, 分别记为sumA 和 sumB。 如果Alice 把第i个糖果棒给Bob, Bob 用第j个糖果棒和Alice换, 按照题意, 需要找到 A[i] 和 B[j] 使得以下等式成立:
sumA - A[i] + B[j] = sumB - B[j] + A[i]
原始的思路是暴力求解: 对于每一个A[i], 遍历所有的B[j]来求解, 但是会超时。 后来想到题目问的是交换糖果的大小, 不考虑顺序, 就尝试用二分法优化了一下查找B[j]的过程。这样一来就能通过所有测试了。
三、AC 代码:
class Solution {
public:
vector<int> fairCandySwap(vector<int>& A, vector<int>& B) {
int sumA = 0, sumB = 0;
// 求Alice数组的和
for (int a = 0; a < A.size(); a++) {
sumA += A[a];
}
// 求Bob数组的和
for (int b = 0; b < B.size(); b++) {
sumB += B[b];
}
vector<int> result(2, 0);
int left = 0, right = B.size() - 1;
int midb = left + (right - left)/2;
//对两个数组排序
sort(A.begin(), A.end());
sort(B.begin(), B.end());
for (int i = 0; i < A.size(); i++) {
// 找到Alice给出第i个糖果之后所剩的糖果大小的和
int newSumA = sumA - A[i];
left = 0;
right = B.size() - 1;
// 用二分法找Bob 要交换的糖果大小
while (left <= right && left >= 0 && right >= 0) {
midb = left + (right - left)/2;
int newSumB = sumB - B[midb];
// Bob 需要找小一些的糖果
if (newSumA + B[midb] > newSumB + A[i]) {
right = midb - 1;
// Bob 需要找大一些的糖果大小
}else if (newSumA + B[midb] < newSumB + A[i]) {
left = midb + 1;
// 正好找到了合适的糖果大小
// 存起来
}else {
result[0] = A[i];
result[1] = B[midb];
return result;
}
}
}
return result;
}
};