跳转至

2561. 重排水果

题目描述

你有两个果篮,每个果篮中有 n 个水果。给你两个下标从 0 开始的整数数组 basket1basket2 ,用以表示两个果篮中每个水果的交换成本。你想要让两个果篮相等。为此,可以根据需要多次执行下述操作:

  • 选中两个下标 ij ,并交换 basket1 中的第 i 个水果和 basket2 中的第 j 个水果。
  • 交换的成本是 min(basket1i,basket2j)

根据果篮中水果的成本进行排序,如果排序后结果完全相同,则认为两个果篮相等。

返回使两个果篮相等的最小交换成本,如果无法使两个果篮相等,则返回 -1

 

示例 1:

输入:basket1 = [4,2,2,2], basket2 = [1,4,1,2]
输出:1
解释:交换 basket1 中下标为 1 的水果和 basket2 中下标为 0 的水果,交换的成本为 1 。此时,basket1 = [4,1,2,2] 且 basket2 = [2,4,1,2] 。重排两个数组,发现二者相等。

示例 2:

输入:basket1 = [2,3,4,1], basket2 = [3,2,5,1]
输出:-1
解释:可以证明无法使两个果篮相等。

 

提示:

  • basket1.length == bakste2.length
  • 1 <= basket1.length <= 105
  • 1 <= basket1i,basket2i <= 109

解法

方法一:贪心 + 构造

我们可以先将两个数组中共有的元素去掉,对于剩下的每个数字,其出现的次数必须为偶数,否则无法构造出相同的数组。不妨记去除共有元素后,两数组分别为 \(a\)\(b\)

接下来,我们考虑如何进行交换。

如果我们要交换 \(a\) 中最小的数,那么我们要在 \(b\) 中找到最大的数,与其进行交换;同理,如果我们要交换 \(b\) 中最小的数,那么我们要在 \(a\) 中找到最大的数,与其进行交换。可以通过排序来实现。

不过,还有另一种交换的方案,我们可以借助一个最小的数 \(mi\) 作为过渡元素,将 \(a\) 中的数先与 \(mi\) 进行交换,再将 \(mi\)\(b\) 中的数进行交换。这样,交换的成本为 \(2 \times mi\)

在代码实现上,我们可以直接将数组 \(a\)\(b\) 合并成数组 \(nums\),然后对数组 \(nums\) 进行排序。接下来枚举前一半的数,计算每次的最小成本,累加到答案中即可。

时间复杂度 \(O(n \times \log n)\),空间复杂度 \(O(n)\)。其中 \(n\) 为数组长度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Solution:
    def minCost(self, basket1: List[int], basket2: List[int]) -> int:
        cnt = Counter()
        for a, b in zip(basket1, basket2):
            cnt[a] += 1
            cnt[b] -= 1
        mi = min(cnt)
        nums = []
        for x, v in cnt.items():
            if v % 2:
                return -1
            nums.extend([x] * (abs(v) // 2))
        nums.sort()
        m = len(nums) // 2
        return sum(min(x, mi * 2) for x in nums[:m])
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
    public long minCost(int[] basket1, int[] basket2) {
        int n = basket1.length;
        Map<Integer, Integer> cnt = new HashMap<>();
        for (int i = 0; i < n; ++i) {
            cnt.merge(basket1[i], 1, Integer::sum);
            cnt.merge(basket2[i], -1, Integer::sum);
        }
        int mi = 1 << 30;
        List<Integer> nums = new ArrayList<>();
        for (var e : cnt.entrySet()) {
            int x = e.getKey(), v = e.getValue();
            if (v % 2 != 0) {
                return -1;
            }
            for (int i = Math.abs(v) / 2; i > 0; --i) {
                nums.add(x);
            }
            mi = Math.min(mi, x);
        }
        Collections.sort(nums);
        int m = nums.size();
        long ans = 0;
        for (int i = 0; i < m / 2; ++i) {
            ans += Math.min(nums.get(i), mi * 2);
        }
        return ans;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
    long long minCost(vector<int>& basket1, vector<int>& basket2) {
        int n = basket1.size();
        unordered_map<int, int> cnt;
        for (int i = 0; i < n; ++i) {
            cnt[basket1[i]]++;
            cnt[basket2[i]]--;
        }
        int mi = 1 << 30;
        vector<int> nums;
        for (auto& [x, v] : cnt) {
            if (v % 2) {
                return -1;
            }
            for (int i = abs(v) / 2; i; --i) {
                nums.push_back(x);
            }
            mi = min(mi, x);
        }
        sort(nums.begin(), nums.end());
        int m = nums.size();
        long long ans = 0;
        for (int i = 0; i < m / 2; ++i) {
            ans += min(nums[i], mi * 2);
        }
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
func minCost(basket1 []int, basket2 []int) (ans int64) {
    cnt := map[int]int{}
    for i, a := range basket1 {
        cnt[a]++
        cnt[basket2[i]]--
    }
    mi := 1 << 30
    nums := []int{}
    for x, v := range cnt {
        if v%2 != 0 {
            return -1
        }
        for i := abs(v) / 2; i > 0; i-- {
            nums = append(nums, x)
        }
        mi = min(mi, x)
    }
    sort.Ints(nums)
    m := len(nums)
    for i := 0; i < m/2; i++ {
        ans += int64(min(nums[i], mi*2))
    }
    return
}

func abs(x int) int {
    if x < 0 {
        return -x
    }
    return x
}

评论