你有两个果篮,每个果篮中有 n
个水果。给你两个下标从 0 开始的整数数组 basket1
和 basket2
,用以表示两个果篮中每个水果的交换成本。你想要让两个果篮相等。为此,可以根据需要多次执行下述操作:
- 选中两个下标
i
和j
,并交换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 <= 10^5
1 <= basket1i,basket2i <= 10^9
分析:先用哈希表分别记录两个果篮里出现过的水果成本出现次数。想让交换成本尽可能小,有两种方法,一种是用小成本的水果与大成本的水果进行交换;另一种方法是用成本最小的水果,交换两次,举例如下:
[3,4,4] 和 [3,5,5],可以 4 和 5 直接交换,也可以用 3 先交换 5,再用 3 交换 4.
能否使两个果篮相等,取决于所有出现的水果交换成本是否都是偶数。如果存在某个成本出现过奇数次,则一定不可能相等。统计完所有的成本出现次数后,对于每一次交换,都分别检查两种交换结果的大小,取较小的方法进行统计,直到全部交换完。
class Solution {
public:
long long minCost(vector<int>& basket1, vector<int>& basket2) {
sort(basket1.begin(),basket1.end());
sort(basket2.begin(),basket2.end());
int t1=0,t2=0,t=0,mini=1000000001;
map<int,int>cnt1,cnt2;
int val1[100010]={0},val2[100010]={0};
for(int i=0;i<basket1.size();++i)
{
cnt1[basket1[i]]++;mini=fmin(mini,basket1[i]);
if(cnt1[basket1[i]]==1)val1[t1++]=basket1[i];
}
for(int i=0;i<basket2.size();++i)
{
cnt2[basket2[i]]++;mini=fmin(mini,basket2[i]);
if(cnt2[basket2[i]]==1)val2[t2++]=basket2[i];
}
long long ans=0;
//exval表示待交换的成本价格,exnum表示待交换的成本数量,下标一一对应
long long exnum[200010]={0},exval[200010]={0};
//下面的循环用于统计需要交换的成本
for(int i=0,j=0;i<t1||j<t2;)
{
// printf("i=%d j=%d val1=%d val2=%d\n",i,j,val1[i],val2[j]);
if(i<t1&&j<t2)
{
if(val1[i]!=val2[j])//不相等说明小的那个在另一个篮子里不存在,要分一半
{
if(val1[i]<val2[j])
{
if(cnt1[val1[i]]&1)return -1;
exval[t]=val1[i],exnum[t]=cnt1[val1[i]]/2;t++;i++;
}
else
{
if(cnt2[val2[j]]&1)return -1;
exval[t]=val2[j],exnum[t]=cnt2[val2[j]]/2;t++;j++;
}
}
else if(val1[i]==val2[j])//相等则平均分
{
if((cnt1[val1[i]]+cnt2[val2[j]])&1)return -1;
if(cnt1[val1[i]]==cnt2[val2[j]])i++,j++;
else exval[t]=val1[i],exnum[t]=(cnt1[val1[i]]+cnt2[val2[j]])/2-fmin(cnt1[val1[i]],cnt2[val2[j]]),t++,i++,j++;
}
}
else if(i<t1)
{
while(i<t1)
{
if(cnt1[val1[i]]&1)return -1;
exval[t]=val1[i],exnum[t]=cnt1[val1[i]]/2;t++;i++;
}
}
else if(j<t2)
{
while(j<t2)
{
if(cnt2[val2[j]]&1)return -1;
exval[t]=val2[j],exnum[t]=cnt2[val2[j]]/2;t++;j++;
}
}
// printf("i=%d j=%d t1=%d t2=%d\n",i,j,t1,t2);
}
// printf("t=%d\n",t);
// for(int i=0;i<t;++i)
// {
// printf("val=%d num=%d\n",exval[i],exnum[i]);
// }
for(int i=0,j=t-1;i<=j;)//注意每次交换都要比较两种方法的代价
{
if(i==j)ans+=fmin(exval[i]*exnum[j]/2,mini*exnum[j]),exnum[i]-=exnum[j],j--;
else if(exnum[i]>exnum[j])ans+=fmin(exval[i]*exnum[j],2*mini*exnum[j]),exnum[i]-=exnum[j],j--;
else if(exnum[i]==exnum[j])ans+=fmin(exval[i]*exnum[j],2*mini*exnum[j]),j--,i++;
else if(exnum[i]<exnum[j])ans+=fmin(exval[i]*exnum[i],2*mini*exnum[i]),exnum[j]-=exnum[i],i++;
}
return ans;
}
};