Rearranging Fruits
Minimum cost to equalize two baskets by swapping — sort the symmetric-difference half and use the global min as a "courier".
Problem#
Two baskets basket1, basket2. Multiset equal means same frequencies. In one swap, exchange one element from each at cost min(a, b). Return minimum total cost to equalize, or -1.
Examples#
basket1 = [4,2,2,2], basket2 = [1,4,1,2]→1basket1 = [2,3,4,1], basket2 = [3,2,5,1]→-1
Constraints#
1 <= n <= 10^5.
Hints#
Hint 1
Approach#
Count frequency differences diff[v] = count1(v) - count2(v). If any |diff[v]| is odd, return -1. Build two lists: items where diff > 0 (excess in 1) and diff < 0 (excess in 2), each appearing |diff|/2 times. Sort both. Pair smallest-with-largest greedily — direct swap cost is min(a, b). Alternative: use the global minimum as a “courier” — cost 2 * globalMin per swap if cheaper. Take the min across all pairings.
Solution#
class Solution {public: long long minCost(vector<int>& basket1, vector<int>& basket2) { unordered_map<int,int> diff; for (int x : basket1) ++diff[x]; for (int x : basket2) --diff[x]; int globalMin = INT_MAX; vector<int> excess; for (auto& [v, d] : diff) { if (d % 2 != 0) return -1; int half = abs(d) / 2; for (int i = 0; i < half; ++i) excess.push_back(v); globalMin = min(globalMin, v); } sort(excess.begin(), excess.end()); long long cost = 0; int half = excess.size() / 2; for (int i = 0; i < half; ++i) { cost += min((long long)excess[i], 2LL * globalMin); } return cost; }};func minCost(basket1 []int, basket2 []int) int64 { diff := map[int]int{} for _, x := range basket1 { diff[x]++ } for _, x := range basket2 { diff[x]-- } globalMin := math.MaxInt32 excess := []int{} for v, d := range diff { if d%2 != 0 { return -1 } half := d if half < 0 { half = -half } half /= 2 for i := 0; i < half; i++ { excess = append(excess, v) } if v < globalMin { globalMin = v } } sort.Ints(excess) var cost int64 half := len(excess) / 2 for i := 0; i < half; i++ { direct := int64(excess[i]) courier := int64(2 * globalMin) if courier < direct { cost += courier } else { cost += direct } } return cost}from collections import Counterfrom typing import List
class Solution: def minCost(self, basket1: List[int], basket2: List[int]) -> int: diff: Counter = Counter() for x in basket1: diff[x] += 1 for x in basket2: diff[x] -= 1 global_min = min(min(basket1), min(basket2)) excess: List[int] = [] for v, d in diff.items(): if d % 2 != 0: return -1 half = abs(d) // 2 excess.extend([v] * half) excess.sort() cost = 0 half = len(excess) // 2 for i in range(half): cost += min(excess[i], 2 * global_min) return costfunction minCost(basket1, basket2) { const diff = new Map(); for (const x of basket1) diff.set(x, (diff.get(x) || 0) + 1); for (const x of basket2) diff.set(x, (diff.get(x) || 0) - 1); let globalMin = Infinity; const excess = []; for (const [v, d] of diff) { if (d % 2 !== 0) return -1; const half = Math.abs(d) / 2; for (let i = 0; i < half; i++) excess.push(v); if (v < globalMin) globalMin = v; } excess.sort((a, b) => a - b); let cost = 0; const half = excess.length / 2; for (let i = 0; i < half; i++) { cost += Math.min(excess[i], 2 * globalMin); } return cost;}class Solution { public long minCost(int[] basket1, int[] basket2) { Map<Integer, Integer> diff = new HashMap<>(); for (int x : basket1) diff.merge(x, 1, Integer::sum); for (int x : basket2) diff.merge(x, -1, Integer::sum); int globalMin = Integer.MAX_VALUE; List<Integer> excess = new ArrayList<>(); for (Map.Entry<Integer, Integer> e : diff.entrySet()) { int v = e.getKey(), d = e.getValue(); if (d % 2 != 0) return -1; int half = Math.abs(d) / 2; for (int i = 0; i < half; i++) excess.add(v); if (v < globalMin) globalMin = v; } Collections.sort(excess); long cost = 0; int half = excess.size() / 2; for (int i = 0; i < half; i++) { cost += Math.min((long) excess.get(i), 2L * globalMin); } return cost; }}function minCost(basket1: number[], basket2: number[]): number { const diff = new Map<number, number>(); for (const x of basket1) diff.set(x, (diff.get(x) ?? 0) + 1); for (const x of basket2) diff.set(x, (diff.get(x) ?? 0) - 1); let globalMin = Infinity; const excess: number[] = []; for (const [v, d] of diff) { if (d % 2 !== 0) return -1; const half = Math.abs(d) / 2; for (let i = 0; i < half; i++) excess.push(v); if (v < globalMin) globalMin = v; } excess.sort((a, b) => a - b); let cost = 0; const half = excess.length / 2; for (let i = 0; i < half; i++) { cost += Math.min(excess[i], 2 * globalMin); } return cost;}Editorial#
The “courier” trick: instead of swapping a and b directly (cost min(a, b)), swap each with the global minimum m and use m as intermediary — total cost 2m. Whenever 2m < min(a, b), the courier wins. Sorting the bottom half of the excess pool gives the cheapest pairings.
Complexity#
- Time: O((n + m) log (n + m)).
- Space: O(n + m).
Concept revision#
Related#