|
| 1 | +# Rearranging Fruits - Problem #2857 |
| 2 | + |
| 3 | +## Problem Statement |
| 4 | +You have two fruit baskets and `n` fruits. You are given two 0-indexed integer arrays `basket1` and `basket2` representing the cost of fruit in basket1 and basket2 respectively. You want to make both baskets equal. To do so, you can use the following operation as many times as you want: |
| 5 | + |
| 6 | +- Chose two indices `i` and `j`, and swap the `i`th fruit of basket1 with the `j`th fruit of basket2. The cost of this operation is `min(basket1[i], basket2[j])`. |
| 7 | + |
| 8 | +Return the minimum cost to make both baskets equal. If it is impossible to make both baskets equal, return `-1`. |
| 9 | + |
| 10 | +## Examples |
| 11 | +``` |
| 12 | +Input: basket1 = [4,2,2,2], basket2 = [1,4,1,2] |
| 13 | +Output: 1 |
| 14 | +Explanation: Swap index 1 of basket1 with index 0 of basket2, which costs 1. Now both baskets have equal sum. |
| 15 | +
|
| 16 | +Input: basket1 = [2,3,4,1], basket2 = [3,2,5,1] |
| 17 | +Output: -1 |
| 18 | +Explanation: It can be shown that it is impossible to make both baskets equal. |
| 19 | +``` |
| 20 | + |
| 21 | +## Approach |
| 22 | +**Key Insight**: To make both baskets equal, the total sum of both baskets must be equal. If they're not equal, it's impossible. If they are equal, we need to find the minimum cost to rearrange fruits. |
| 23 | + |
| 24 | +**Algorithm**: |
| 25 | +1. Check if the sum of both baskets is equal. If not, return -1. |
| 26 | +2. Count the frequency of each fruit in both baskets. |
| 27 | +3. For each fruit type, if the total count is odd, return -1 (impossible to split equally). |
| 28 | +4. Calculate the excess/deficit for each fruit type. |
| 29 | +5. Sort the excess and deficit arrays. |
| 30 | +6. Use two pointers to match the smallest excess with the smallest deficit, minimizing the cost. |
| 31 | + |
| 32 | +**Why this works**: |
| 33 | +- We need to balance the fruits between baskets |
| 34 | +- The minimum cost is achieved by matching the smallest excess with the smallest deficit |
| 35 | +- Each swap operation costs the minimum of the two fruits being swapped |
| 36 | + |
| 37 | +## Complexity Analysis |
| 38 | +- **Time Complexity**: O(n log n) - Due to sorting the excess and deficit arrays |
| 39 | +- **Space Complexity**: O(n) - To store frequency counts and excess/deficit arrays |
| 40 | + |
| 41 | +## Key Insights |
| 42 | +- Both baskets must have equal total sum |
| 43 | +- Each fruit type must have even total count |
| 44 | +- Optimal matching is greedy: smallest excess with smallest deficit |
| 45 | +- The cost of a swap is the minimum of the two fruits being swapped |
| 46 | + |
| 47 | +## Alternative Approaches |
| 48 | +1. **Brute Force**: Try all possible combinations - O(n!) time, impractical |
| 49 | +2. **Dynamic Programming**: Can be used but overkill for this problem |
| 50 | +3. **Graph-based**: Model as a matching problem, but greedy approach is simpler |
| 51 | + |
| 52 | +## Solutions in Different Languages |
| 53 | + |
| 54 | +### Java |
| 55 | +```java |
| 56 | +// See solution.java |
| 57 | +import java.util.*; |
| 58 | + |
| 59 | +class Solution { |
| 60 | + public long minCost(int[] basket1, int[] basket2) { |
| 61 | + // Check if sums are equal |
| 62 | + long sum1 = 0, sum2 = 0; |
| 63 | + for (int fruit : basket1) sum1 += fruit; |
| 64 | + for (int fruit : basket2) sum2 += fruit; |
| 65 | + |
| 66 | + if (sum1 != sum2) return -1; |
| 67 | + |
| 68 | + // Count frequencies |
| 69 | + Map<Integer, Integer> freq1 = new HashMap<>(); |
| 70 | + Map<Integer, Integer> freq2 = new HashMap<>(); |
| 71 | + |
| 72 | + for (int fruit : basket1) freq1.put(fruit, freq1.getOrDefault(fruit, 0) + 1); |
| 73 | + for (int fruit : basket2) freq2.put(fruit, freq2.getOrDefault(fruit, 0) + 1); |
| 74 | + |
| 75 | + // Check if each fruit type has even total count |
| 76 | + Set<Integer> allFruits = new HashSet<>(); |
| 77 | + allFruits.addAll(freq1.keySet()); |
| 78 | + allFruits.addAll(freq2.keySet()); |
| 79 | + |
| 80 | + for (int fruit : allFruits) { |
| 81 | + int total = freq1.getOrDefault(fruit, 0) + freq2.getOrDefault(fruit, 0); |
| 82 | + if (total % 2 != 0) return -1; |
| 83 | + } |
| 84 | + |
| 85 | + // Calculate excess/deficit |
| 86 | + List<Integer> excess = new ArrayList<>(); |
| 87 | + List<Integer> deficit = new ArrayList<>(); |
| 88 | + |
| 89 | + for (int fruit : allFruits) { |
| 90 | + int count1 = freq1.getOrDefault(fruit, 0); |
| 91 | + int count2 = freq2.getOrDefault(fruit, 0); |
| 92 | + int target = (count1 + count2) / 2; |
| 93 | + |
| 94 | + if (count1 > target) { |
| 95 | + for (int i = 0; i < count1 - target; i++) { |
| 96 | + excess.add(fruit); |
| 97 | + } |
| 98 | + } else if (count2 > target) { |
| 99 | + for (int i = 0; i < count2 - target; i++) { |
| 100 | + deficit.add(fruit); |
| 101 | + } |
| 102 | + } |
| 103 | + } |
| 104 | + |
| 105 | + // Sort for optimal matching |
| 106 | + Collections.sort(excess); |
| 107 | + Collections.sort(deficit); |
| 108 | + |
| 109 | + long cost = 0; |
| 110 | + for (int i = 0; i < excess.size(); i++) { |
| 111 | + cost += Math.min(excess.get(i), deficit.get(i)); |
| 112 | + } |
| 113 | + |
| 114 | + return cost; |
| 115 | + } |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +### JavaScript |
| 120 | +```javascript |
| 121 | +// See solution.js |
| 122 | +/** |
| 123 | + * @param {number[]} basket1 |
| 124 | + * @param {number[]} basket2 |
| 125 | + * @return {number} |
| 126 | + */ |
| 127 | +var minCost = function(basket1, basket2) { |
| 128 | + // Check if sums are equal |
| 129 | + const sum1 = basket1.reduce((sum, fruit) => sum + fruit, 0); |
| 130 | + const sum2 = basket2.reduce((sum, fruit) => sum + fruit, 0); |
| 131 | + |
| 132 | + if (sum1 !== sum2) return -1; |
| 133 | + |
| 134 | + // Count frequencies |
| 135 | + const freq1 = new Map(); |
| 136 | + const freq2 = new Map(); |
| 137 | + |
| 138 | + for (const fruit of basket1) { |
| 139 | + freq1.set(fruit, (freq1.get(fruit) || 0) + 1); |
| 140 | + } |
| 141 | + for (const fruit of basket2) { |
| 142 | + freq2.set(fruit, (freq2.get(fruit) || 0) + 1); |
| 143 | + } |
| 144 | + |
| 145 | + // Check if each fruit type has even total count |
| 146 | + const allFruits = new Set([...freq1.keys(), ...freq2.keys()]); |
| 147 | + |
| 148 | + for (const fruit of allFruits) { |
| 149 | + const total = (freq1.get(fruit) || 0) + (freq2.get(fruit) || 0); |
| 150 | + if (total % 2 !== 0) return -1; |
| 151 | + } |
| 152 | + |
| 153 | + // Calculate excess/deficit |
| 154 | + const excess = []; |
| 155 | + const deficit = []; |
| 156 | + |
| 157 | + for (const fruit of allFruits) { |
| 158 | + const count1 = freq1.get(fruit) || 0; |
| 159 | + const count2 = freq2.get(fruit) || 0; |
| 160 | + const target = (count1 + count2) / 2; |
| 161 | + |
| 162 | + if (count1 > target) { |
| 163 | + for (let i = 0; i < count1 - target; i++) { |
| 164 | + excess.push(fruit); |
| 165 | + } |
| 166 | + } else if (count2 > target) { |
| 167 | + for (let i = 0; i < count2 - target; i++) { |
| 168 | + deficit.push(fruit); |
| 169 | + } |
| 170 | + } |
| 171 | + } |
| 172 | + |
| 173 | + // Sort for optimal matching |
| 174 | + excess.sort((a, b) => a - b); |
| 175 | + deficit.sort((a, b) => a - b); |
| 176 | + |
| 177 | + let cost = 0; |
| 178 | + for (let i = 0; i < excess.length; i++) { |
| 179 | + cost += Math.min(excess[i], deficit[i]); |
| 180 | + } |
| 181 | + |
| 182 | + return cost; |
| 183 | +}; |
| 184 | +``` |
| 185 | + |
| 186 | +## Test Cases |
| 187 | +``` |
| 188 | +Test Case 1: basket1 = [4,2,2,2], basket2 = [1,4,1,2] → 1 |
| 189 | +Test Case 2: basket1 = [2,3,4,1], basket2 = [3,2,5,1] → -1 |
| 190 | +Test Case 3: basket1 = [1,1,1,1], basket2 = [1,1,1,1] → 0 |
| 191 | +Test Case 4: basket1 = [1,2,3], basket2 = [1,2,3] → 0 |
| 192 | +``` |
| 193 | + |
| 194 | +## Edge Cases |
| 195 | +- Baskets already equal (cost = 0) |
| 196 | +- Impossible to make equal (return -1) |
| 197 | +- Single fruit in each basket |
| 198 | +- All fruits are the same |
| 199 | +- Large numbers (use long in Java) |
| 200 | + |
| 201 | +## Related Problems |
| 202 | +- Two Sum |
| 203 | +- Minimum Swaps to Make Sequences Equal |
| 204 | +- Partition Equal Subset Sum |
0 commit comments