Skip to content

Commit ee0682f

Browse files
Update Rearranging Fruits solution with optimized approach and add Python solution
1 parent 4f56c50 commit ee0682f

File tree

3 files changed

+198
-105
lines changed

3 files changed

+198
-105
lines changed

Hard/2025-08-02-2857-RearrangingFruits/explanation.md

Lines changed: 106 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,20 @@ Explanation: It can be shown that it is impossible to make both baskets equal.
1919
```
2020

2121
## 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.
22+
**Key Insight**: To make both baskets equal, we need to balance the fruits between them. The key optimization is using the minimum value in both baskets to potentially reduce swap costs.
2323

2424
**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.
25+
1. Count the frequency of each fruit in both baskets and find the minimum value.
26+
2. For each fruit type, check if the total count is odd (impossible to split equally).
27+
3. Calculate excess fruits for each basket (fruits that need to be moved out).
28+
4. Sort one list in ascending order and the other in descending order for optimal matching.
29+
5. Calculate the minimum cost considering both direct swaps and using the minimum value as an intermediary.
3130

3231
**Why this works**:
3332
- 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
33+
- The minimum cost is achieved by matching optimally
34+
- Using the minimum value as an intermediary can sometimes reduce costs (2 * minVal vs direct swap)
35+
- Sorting in opposite directions ensures optimal pairing
3636

3737
## Complexity Analysis
3838
- **Time Complexity**: O(n log n) - Due to sorting the excess and deficit arrays
@@ -58,60 +58,56 @@ import java.util.*;
5858

5959
class Solution {
6060
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;
61+
int n = basket1.length;
62+
63+
Map<Integer, Integer> map1 = new HashMap<>();
64+
Map<Integer, Integer> map2 = new HashMap<>();
65+
int minVal = Integer.MAX_VALUE;
66+
67+
for(int i = 0; i < n; i++){
68+
map1.put(basket1[i], map1.getOrDefault(basket1[i], 0) + 1);
69+
map2.put(basket2[i], map2.getOrDefault(basket2[i], 0) + 1);
70+
minVal = Math.min(minVal, basket1[i]);
71+
minVal = Math.min(minVal, basket2[i]);
8372
}
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);
73+
74+
List<Integer> swapList1 = new ArrayList<>();
75+
for(int key: map1.keySet()){
76+
int c1 = map1.get(key);
77+
int c2 = map2.getOrDefault(key, 0);
78+
if((c1 + c2) % 2 == 1) return -1;
79+
if(c1 > c2){
80+
int addCnt = (c1 - c2) / 2;
81+
while(addCnt-- > 0){
82+
swapList1.add(key);
9783
}
98-
} else if (count2 > target) {
99-
for (int i = 0; i < count2 - target; i++) {
100-
deficit.add(fruit);
84+
}
85+
}
86+
87+
List<Integer> swapList2 = new ArrayList<>();
88+
for(int key: map2.keySet()){
89+
int c1 = map1.getOrDefault(key, 0);
90+
int c2 = map2.get(key);
91+
if((c1 + c2) % 2 == 1) return -1;
92+
if(c2 > c1){
93+
int addCnt = (c2 - c1) / 2;
94+
while(addCnt-- > 0){
95+
swapList2.add(key);
10196
}
10297
}
10398
}
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));
99+
100+
Collections.sort(swapList1);
101+
Collections.sort(swapList2, (a, b) -> b - a);
102+
103+
long res = 0;
104+
for(int i = 0; i < swapList1.size(); i++){
105+
res += Math.min(2 * minVal,
106+
Math.min(swapList1.get(i), swapList2.get(i))
107+
);
112108
}
113-
114-
return cost;
109+
110+
return res;
115111
}
116112
}
117113
```
@@ -183,6 +179,59 @@ var minCost = function(basket1, basket2) {
183179
};
184180
```
185181

182+
### Python
183+
```python
184+
# See solution.py
185+
from collections import defaultdict
186+
from typing import List
187+
188+
class Solution:
189+
def minCost(self, basket1: List[int], basket2: List[int]) -> int:
190+
n = len(basket1)
191+
192+
map1 = defaultdict(int)
193+
map2 = defaultdict(int)
194+
min_val = float('inf')
195+
196+
for i in range(n):
197+
map1[basket1[i]] += 1
198+
map2[basket2[i]] += 1
199+
min_val = min(min_val, basket1[i])
200+
min_val = min(min_val, basket2[i])
201+
202+
swap_list1 = []
203+
for key in map1:
204+
c1 = map1[key]
205+
c2 = map2.get(key, 0)
206+
if (c1 + c2) % 2 == 1:
207+
return -1
208+
if c1 > c2:
209+
add_cnt = (c1 - c2) // 2
210+
for _ in range(add_cnt):
211+
swap_list1.append(key)
212+
213+
swap_list2 = []
214+
for key in map2:
215+
c1 = map1.get(key, 0)
216+
c2 = map2[key]
217+
if (c1 + c2) % 2 == 1:
218+
return -1
219+
if c2 > c1:
220+
add_cnt = (c2 - c1) // 2
221+
for _ in range(add_cnt):
222+
swap_list2.append(key)
223+
224+
swap_list1.sort()
225+
swap_list2.sort(reverse=True)
226+
227+
res = 0
228+
for i in range(len(swap_list1)):
229+
res += min(2 * min_val,
230+
min(swap_list1[i], swap_list2[i]))
231+
232+
return res
233+
```
234+
186235
## Test Cases
187236
```
188237
Test Case 1: basket1 = [4,2,2,2], basket2 = [1,4,1,2] → 1

Hard/2025-08-02-2857-RearrangingFruits/solution.java

Lines changed: 44 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,55 @@
22

33
class Solution {
44
public long minCost(int[] basket1, int[] basket2) {
5-
// Check if sums are equal
6-
long sum1 = 0, sum2 = 0;
7-
for (int fruit : basket1) sum1 += fruit;
8-
for (int fruit : basket2) sum2 += fruit;
9-
10-
if (sum1 != sum2) return -1;
11-
12-
// Count frequencies
13-
Map<Integer, Integer> freq1 = new HashMap<>();
14-
Map<Integer, Integer> freq2 = new HashMap<>();
15-
16-
for (int fruit : basket1) freq1.put(fruit, freq1.getOrDefault(fruit, 0) + 1);
17-
for (int fruit : basket2) freq2.put(fruit, freq2.getOrDefault(fruit, 0) + 1);
18-
19-
// Check if each fruit type has even total count
20-
Set<Integer> allFruits = new HashSet<>();
21-
allFruits.addAll(freq1.keySet());
22-
allFruits.addAll(freq2.keySet());
23-
24-
for (int fruit : allFruits) {
25-
int total = freq1.getOrDefault(fruit, 0) + freq2.getOrDefault(fruit, 0);
26-
if (total % 2 != 0) return -1;
5+
int n = basket1.length;
6+
7+
Map<Integer, Integer> map1 = new HashMap<>();
8+
Map<Integer, Integer> map2 = new HashMap<>();
9+
int minVal = Integer.MAX_VALUE;
10+
11+
for(int i = 0; i < n; i++){
12+
map1.put(basket1[i], map1.getOrDefault(basket1[i], 0) + 1);
13+
map2.put(basket2[i], map2.getOrDefault(basket2[i], 0) + 1);
14+
minVal = Math.min(minVal, basket1[i]);
15+
minVal = Math.min(minVal, basket2[i]);
2716
}
28-
29-
// Calculate excess/deficit
30-
List<Integer> excess = new ArrayList<>();
31-
List<Integer> deficit = new ArrayList<>();
32-
33-
for (int fruit : allFruits) {
34-
int count1 = freq1.getOrDefault(fruit, 0);
35-
int count2 = freq2.getOrDefault(fruit, 0);
36-
int target = (count1 + count2) / 2;
37-
38-
if (count1 > target) {
39-
for (int i = 0; i < count1 - target; i++) {
40-
excess.add(fruit);
17+
18+
List<Integer> swapList1 = new ArrayList<>();
19+
for(int key: map1.keySet()){
20+
int c1 = map1.get(key);
21+
int c2 = map2.getOrDefault(key, 0);
22+
if((c1 + c2) % 2 == 1) return -1;
23+
if(c1 > c2){
24+
int addCnt = (c1 - c2) / 2;
25+
while(addCnt-- > 0){
26+
swapList1.add(key);
4127
}
42-
} else if (count2 > target) {
43-
for (int i = 0; i < count2 - target; i++) {
44-
deficit.add(fruit);
28+
}
29+
}
30+
31+
List<Integer> swapList2 = new ArrayList<>();
32+
for(int key: map2.keySet()){
33+
int c1 = map1.getOrDefault(key, 0);
34+
int c2 = map2.get(key);
35+
if((c1 + c2) % 2 == 1) return -1;
36+
if(c2 > c1){
37+
int addCnt = (c2 - c1) / 2;
38+
while(addCnt-- > 0){
39+
swapList2.add(key);
4540
}
4641
}
4742
}
48-
49-
// Sort for optimal matching
50-
Collections.sort(excess);
51-
Collections.sort(deficit);
52-
53-
long cost = 0;
54-
for (int i = 0; i < excess.size(); i++) {
55-
cost += Math.min(excess.get(i), deficit.get(i));
43+
44+
Collections.sort(swapList1);
45+
Collections.sort(swapList2, (a, b) -> b - a);
46+
47+
long res = 0;
48+
for(int i = 0; i < swapList1.size(); i++){
49+
res += Math.min(2 * minVal,
50+
Math.min(swapList1.get(i), swapList2.get(i))
51+
);
5652
}
57-
58-
return cost;
53+
54+
return res;
5955
}
6056
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from collections import defaultdict
2+
from typing import List
3+
4+
class Solution:
5+
def minCost(self, basket1: List[int], basket2: List[int]) -> int:
6+
n = len(basket1)
7+
8+
map1 = defaultdict(int)
9+
map2 = defaultdict(int)
10+
min_val = float('inf')
11+
12+
for i in range(n):
13+
map1[basket1[i]] += 1
14+
map2[basket2[i]] += 1
15+
min_val = min(min_val, basket1[i])
16+
min_val = min(min_val, basket2[i])
17+
18+
swap_list1 = []
19+
for key in map1:
20+
c1 = map1[key]
21+
c2 = map2.get(key, 0)
22+
if (c1 + c2) % 2 == 1:
23+
return -1
24+
if c1 > c2:
25+
add_cnt = (c1 - c2) // 2
26+
for _ in range(add_cnt):
27+
swap_list1.append(key)
28+
29+
swap_list2 = []
30+
for key in map2:
31+
c1 = map1.get(key, 0)
32+
c2 = map2[key]
33+
if (c1 + c2) % 2 == 1:
34+
return -1
35+
if c2 > c1:
36+
add_cnt = (c2 - c1) // 2
37+
for _ in range(add_cnt):
38+
swap_list2.append(key)
39+
40+
swap_list1.sort()
41+
swap_list2.sort(reverse=True)
42+
43+
res = 0
44+
for i in range(len(swap_list1)):
45+
res += min(2 * min_val,
46+
min(swap_list1[i], swap_list2[i]))
47+
48+
return res

0 commit comments

Comments
 (0)