Observations
- By problem constraints, the two baskets have the same number of fruits. As a result, if one fruit type is in excess in
basket1, some other fruit types inbasket2will together match that excess. - In the end the two baskets must look the same in sorted order. Therefore, in the end, each type of fruit must appear same number of times in both baskets. In other words, if there is a solution, initially each fruit type must be present even number of times in total – across the two baskets. We use this to confirm a solution exists.
- If a fruit type appears
times in excess in
basket1, we need to makeswaps to distribute it evenly between the two baskets. Since each fruit type had even count to begin with, the excess must also be even. Because sum of two numbers (
basket1count andbasket2count) can be even, only if both numbers are even or both numbers are odd. Difference (excess) of two even numbers or two odd numbers is even. - An excess in a basket makes a swap required. And to minimize swap cost we swap the smallest excess from
basket1with the biggest excess frombasket2. - There are two ways we can swap a fruit (say
a) frombasket1with a fruit frombasket2(sayb). The swap cost will be the minimum of these two:- We can directly swap
aandb. Swap cost then ismin(a, b). - We can
swap(a, min_cost)and thenswap(b, min_cost). Swap cost then ismin(a, min_cost) + min(b, min_cost) = 2 * min_cost.
- We can directly swap
Time: , space:
.
from collections import Counter
class Solution:
def minCost(self, basket1: List[int], basket2: List[int]) -> int:
cost_counts = Counter(basket1+basket2)
if any( (count % 2 == 1 for count in cost_counts.values()) ):
return -1
basket1_counts = Counter(basket1)
basket2_counts = Counter(basket2)
basket1_excess, basket2_excess = [], []
for cost in cost_counts.keys():
# If basket1_counts was not initialized with some cost
# basket1_counts[cost] defauls to 0. As if, dict.get(cost, 0).
delta = basket1_counts[cost] - basket2_counts[cost]
if delta == 0: # No swaps needed
continue
# Moving half of the excess balances
# the two baskets for a fruit type
# So, we need |delta|//2 swaps.
repeat_count = abs(delta)//2
if delta > 0:
basket1_excess.extend( [cost] * repeat_count )
else:
basket2_excess.extend( [cost] * repeat_count )
# Consider swapping biggest cost with smallest cost.
# That way swap cost, min(biggest_cost, smallest_cost), is minimized.
basket1_excess.sort()
basket2_excess.sort(reverse=True)
# We can swap a and b through min_element
# swap(a, min_element), swap(b, min_element)
indirect_swap_cost = 2*min(cost_counts.keys())
total_cost = 0
# This loop iterates through every required swap.
# Since the two baskets have the same length (constraints)
# the excesses must have same length as well.
for cost1, cost2 in zip(basket1_excess, basket2_excess, strict=True):
direct_swap_cost = min(cost1, cost2)
total_cost += min( direct_swap_cost, indirect_swap_cost )
return total_cost
Leave a comment