- 通过最少操作次数使数组的和相等
中等
174
相关企业
给你两个长度可能不等的整数数组 nums1 和 nums2 。两个数组中的所有值都在 1 到 6 之间(包含 1 和 6)。
每次操作中,你可以选择 任意 数组中的任意一个整数,将它变成 1 到 6 之间 任意 的值(包含 1 和 6)。
请你返回使 nums1 中所有数的和与 nums2 中所有数的和相等的最少操作次数。如果无法使两个数组的和相等,请返回 -1 。
示例 1:
输入:nums1 = [1,2,3,4,5,6], nums2 = [1,1,2,2,2,2]
输出:3
解释:你可以通过 3 次操作使 nums1 中所有数的和与 nums2 中所有数的和相等。以下数组下标都从 0 开始。
- 将 nums2[0] 变为 6 。 nums1 = [1,2,3,4,5,6], nums2 = [6,1,2,2,2,2] 。
- 将 nums1[5] 变为 1 。 nums1 = [1,2,3,4,5,1], nums2 = [6,1,2,2,2,2] 。
- 将 nums1[2] 变为 2 。 nums1 = [1,2,2,4,5,1], nums2 = [6,1,2,2,2,2] 。
示例 2:
输入:nums1 = [1,1,1,1,1,1,1], nums2 = [6]
输出:-1
解释:没有办法减少 nums1 的和或者增加 nums2 的和使二者相等。
示例 3:
输入:nums1 = [6,6], nums2 = [1]
输出:3
解释:你可以通过 3 次操作使 nums1 中所有数的和与 nums2 中所有数的和相等。以下数组下标都从 0 开始。
- 将 nums1[0] 变为 2 。 nums1 = [2,6], nums2 = [1] 。
- 将 nums1[1] 变为 2 。 nums1 = [2,2], nums2 = [1] 。
- 将 nums2[0] 变为 4 。 nums1 = [2,2], nums2 = [4] 。
提示:
1 <= nums1.length, nums2.length <= 105
1 <= nums1[i], nums2[i] <= 6
题解
这个题目比较巧妙的地方在于,因为可以任意修改元素到[1,6],所以只要两个数组不出现极端的情况,比如一个数组全部变成6的和都没有另外一个数组全部变成1的和大,那么都是可以处理成两个数组和一致的。
为了方便处理,我们把数组排序,并且保证第1个数组的和一定大于等于第2个,那么从贪心的角度来说,我们肯定希望第一个数组的尾部变小,或者第2个数组的头部变大,于是我们每次操作就判断下修改第一个数组还是第2个数组收益更大就好。
AC代码
class Solution {
public:
int minOperations(vector<int>& nums1, vector<int>& nums2)
{
if(nums1.size()>nums2.size()*6 || nums1.size()*6<nums2.size())return -1;
int sum1 = 0, sum2 = 0;
for(int i=0;i<nums1.size();i++)
sum1 += nums1[i];
for(int i=0;i<nums2.size();i++)
sum2 += nums2[i];
if(sum1 == sum2)return 0;
//保证nums1一定大于num2,主要方便后面的计算处理
if(sum1<sum2)
{
swap(nums1, nums2);
swap(sum1, sum2);
}
sort(nums1.begin(),nums1.end());
sort(nums2.begin(),nums2.end());
//因为nums1的和一定大于num2,所以目标转换成了让num1不断减小,让num2不断变大
//从贪心的角度来看,排序后,num1从尾部向头部遍历减小会更好些
//同理排序后,num2从头部向尾部遍历增大会更好些
int t=nums1.size()-1, s=0;
int total = 0;
while(s<nums2.size()&&t>=0)
{
int x1 = nums1[t], x2=nums2[s];
for(int num=nums1[t];num>=1;num--)
{
if(sum1 - nums1[t]+num >= sum2)
{
x1 = num;
}
else break;
}
for(int num=nums2[s];num<=6;num++)
{
if(sum2-nums2[s]+num<=sum1)
{
x2 = num;
}
else break;
}
//说明修改nums2收益更大
if(sum1-(sum2-nums2[s]+x2)<=sum1-nums1[t]+x1-sum2)
{
sum2 = sum2 - nums2[s] + x2;
s += 1;
}
else
{
//说明修改nums1收益更大
sum1 = sum1 - nums1[t] + x1;
t -= 1;
}
total += 1;
if(sum1==sum2)return total;
}
while(s<nums2.size())
{
int x2 = nums2[s];
for(int num=nums2[s];num<=6;num++)
{
if(sum2-nums2[s]+num<=sum1)
{
x2 = num;
}
else break;
}
sum2 = sum2 - nums2[s] + x2;
s += 1;
total += 1;
if(sum1==sum2)return total;
}
while(t>=0)
{
int x1 = nums1[t];
for(int num=nums1[t];num>=1;num--)
{
if(sum1 - nums1[t]+num >= sum2)
{
x1 = num;
}
else break;
}
sum1 = sum1 - nums1[t] + x1;
t -= 1;
total += 1;
if(sum1==sum2)return total;
}
return -1;
}
};