2333贪心

35 阅读3分钟

题目连接:2333. 最小差值平方和 - 力扣(LeetCode)

给你两个下标从 0 开始的整数数组 nums1nums2 ,长度为 n

数组 nums1nums2差值平方和 定义为所有满足 0 <= i < n(nums1[i] - nums2[i])2 之和。

同时给你两个正整数 k1k2 。你可以将 nums1 中的任意元素 +1 或者 -1 至多 k1 次。类似的,你可以将 nums2 中的任意元素 +1 或者 -1 至多 k2 次。

请你返回修改数组 nums1 至多 k1 次且修改数组 nums2 至多 k2 次后的最小 差值平方和

注意: 你可以将数组中的元素变成 整数。

示例 1:

输入:nums1 = [1,2,3,4], nums2 = [2,10,20,19], k1 = 0, k2 = 0
输出:579
解释:nums1 和 nums2 中的元素不能修改,因为 k1 = 0 和 k2 = 0 。
差值平方和为:(1 - 2)2 + (2 - 10)2 + (3 - 20)2 + (4 - 19)2 = 579

示例 2:

输入:nums1 = [1,4,10,12], nums2 = [5,8,6,9], k1 = 1, k2 = 1
输出:43
解释:一种得到最小差值平方和的方式为:
- 将 nums1[0] 增加一次。
- 将 nums2[2] 增加一次。
最小差值平方和为:
(2 - 5)2 + (4 - 8)2 + (10 - 7)2 + (12 - 9)2 = 43 。
注意,也有其他方式可以得到最小差值平方和,但没有得到比 43 更小答案的方案。

提示:

  • n == nums1.length == nums2.length
  • 1 <= n <= 105
  • 0 <= nums1[i], nums2[i] <= 105
  • 0 <= k1, k2 <= 109

思路不难,先计算出每个位置的差值,然后尽可能减小差值。

第一次,写到一半没头绪了:

class Solution {
public:
    long long minSumSquareDiff(vector<int>& nums1, vector<int>& nums2, int k1, int k2) {
        int n=nums1.size();
        long long ans=0;
        vector<int>gap(n);
        for(int i=0;i<n;i++) {
            gap.push_back(abs(nums1[i]-nums2[i]));
        }
        sort(gap.begin(),gap.end());
    }
};

把gap数组排序之后,又如何处理两个k呢?直接将差值最大的变为0,一定就能保证最小吗?

但是我们知道尽可能让gap数组中的差值变小是没问题的。所以我们不妨这样:gap[i]记录差值i+1出现的次数。然后我们令k=k1+k2(因为只是计算差值,所以哪个k作用在哪个数组上已经无关紧要),然后通过消耗k,减少最大的数出现的次数,直到k被消耗完。

class Solution {
public:
    long long minSumSquareDiff(vector<int>& nums1, vector<int>& nums2, int k1, int k2) {
        vector<int>gap(1e5+5,0);//因为数组元素在[0,1e5]内
        int n=nums1.size();
        for(int i=0;i<n;i++) {
            gap[abs(nums1[i]-nums2[i])]++;
        }
        int k=k1+k2;
        for(int i=gap.size()-1;k>0&&i>0;i--) {
            int change=min(k,gap[i]);//减小量
            k-=change;//消耗k
            gap[i-1]+=change;
            gap[i]-=change;
        }
        long long ans=0;
        for(long long i=0;i<gap.size();i++) {
            if(gap[i]) {
                ans+=(i*i*gap[i]);
            }
        }
        return ans;
    }
};

解释:假设差值分别为[1,2,2,3]且k=4,那么gap[1]=1,gap[2]=2,gap[3]=1.

从最后一个元素开始,change=1,因此消耗1个单位,让差值为3的那个对子变成差值为2,因此gap[2]要加一,gap[3]要减一,k也要减一。也就是说,我们的贪心策略是:尽可能减小大差值出现的次数。