2561. 重排水果
Problem: 2561. 重排水果
文章目录
- 思路
- 解题过程
- 复杂度
- Code
思路
-
首先,去掉两个数组的交集,不需要交换。去掉后,每个剩余数字在两个数组中的总出现次数必须为偶数,这样才能均分。
-
之后,经过一系列猜想,在每个数至多交换一次的前提下,最优交换方式是把一个从小到大排序,另一个从大到小排序,然后交换 ai 和 bi。
-
又因为没说不可以交换两次,如果两个数组里有一个全局最小值 min_val(两个篮子所有元素里的最小值),用 min_val 当 “中介”,可能让交换成本更低 。
-
可以分两步:
- 交换 basket1 里的 min_val 和 basket2 里的 bi → 此时 min_val 到了 basket2,bi 到了 basket1。
- 交换 basket2 里的 min_val 和 basket1 里的 ai → 此时 min_val 回到 basket1,ai 到了 basket2。
这两次交换后,ai 和 bi 完成交换,且 min_val 又回到了最初的数组里(相当于 “来回跳了一次,位置没变” )。
这两次交换的成本是:
2·min_val
。
-
解题过程
- 首先使用哈希表统计两个篮子中每个元素的出现次数。
- 检查所有元素的总数量是否为偶数,若有元素总数为奇数则无法平衡,返回 - 1。
- 找出两个篮子中需要交换的元素,计算每个元素需要交换的数量。
- 找到两个篮子中的最小值,用于计算间接交换的成本。
- 对需要交换的元素进行排序,通过比较直接交换和间接交换(通过最小值中转)的成本,选择最小成本累加。
复杂度
- 时间复杂度: O(nlogN)O(nlogN)O(nlogN)
- 空间复杂度: O(n)O(n)O(n)
Code
class Solution {
public:long long minCost(vector<int>& basket1, vector<int>& basket2) {unordered_map<int, int> cnt1, cnt2, total;// 统计两个篮子中元素的出现次数for (int num : basket1) {cnt1[num]++;total[num]++;}for (int num : basket2) {cnt2[num]++;total[num]++;}// 检查每个元素的总数是否为偶数,若有奇数则不可能平衡for (auto& [num, count] : total) {if (count % 2 != 0)return -1;}// 找出需要交换的元素vector<int> diff1, diff2;for (auto& [num, count] : cnt1) {int other = cnt2[num];if (count > other) {int need = (count - other) / 2;for (int i = 0; i < need; i++) {diff1.push_back(num);}}}for (auto& [num, count] : cnt2) {int other = cnt1[num];if (count > other) {int need = (count - other) / 2;for (int i = 0; i < need; i++) {diff2.push_back(num);}}}// 找到两个篮子中的最小值int min_val = INT_MAX;for (int num : basket1)min_val = min(min_val, num);for (int num : basket2)min_val = min(min_val, num);// 计算最小成本long long cost = 0;sort(diff1.begin(), diff1.end());sort(diff2.rbegin(), diff2.rend()); // 降序排列for (int i = 0; i < diff1.size(); i++) {cost +=min({diff1[i], diff2[i], 2 * min_val});}return cost;}
};