手套
题目描述:
在地下室里放着n种颜色的手套,手套分左右手,但是每种颜色的左右手手套个数不一定相同。A先生现在要出门,所以他要去地下室选手套。但是昏暗的灯光让他无法分辨手套的颜色,只能分辨出左右手。所以他会多拿一些手套,然后选出一双颜色相同的左右手手套。现在的问题是,他至少要拿多少只手套(左手加右手),才能保证一定能选出一双颜色相同的手套。
给定颜色种数n(1≤n≤13),同时给定两个长度为n的数组left,right,分别代表每种颜色左右手手套的数量。数据保证左右的手套总数均不超过26,且一定存在至少一种合法方案。
题目链接:
链接:https://www.nowcoder.com/questionTerminal/365d5722fff640a0b6684391153e58d8
测试样例:
4,[0,7,1,6],[1,5,0,6]
返回:10(解释:可以左手手套取2只,右手手套取8只)
解题思路:
这是一道与贪心算法有的题目:贪心算法可以说是一种自然智慧。
我们首先来想一个问题:我们左右两个桌子上面分别放了左手手套和右手手套,并且有n种颜色的手套(每种颜色的手套数都是>=1)。那我们至少要拿多少只手套才能保证一定选出一双颜色相同的手套呢?是不是我们只需要在左手手套或者右手手套中把所有颜色的单只手套都拿一只,然后再在另外一边手套中任意拿一个手套,我们就能够在拿手套数最少的前提下保证我们一定能够选出一双颜色相同的手套。
但是现在题目并不是直接在桌子上面放着左手手套和右手手套,而是在地下室里面放着n种颜色的手套,手套分左右手,每种颜色的左右手手套个数不一定相同,并且每种颜色的左右手手套的个数还有可能是0。那么加了这些限制条件之后,我们如何才能够在拿手套数最少的前提下保证我们一定能够选出一双颜色相同的手套呢?
这次我们的拿法和上面稍微有点不一样,我们首先需要统计一边手套颜色为0的手套个数、另一边手套不为0的废数据、左边手套的的总数、左边手套颜色最少的手套个数以及右边手套的总数、右边手套颜色最少的手套个数。大家可能不太清楚为什么要这么做,不要着急,下面我来为大家解释。
首先来解释一下为什么要记录另一边手套数不为0的废数据:假如我们把左手手套的总数求出来了,但是你左边某个颜色的手套数为0,那么对应的右边相应颜色的手套数不为0,即使你把左手手套的总数都求出来了,那也不能够保证你左边手套拿完之后再去右边手套拿一只就一定能够选出一双颜色相同的手套。这是因为你左边某个颜色手套数为0的手套,它对应的右边的手套这些已经是废数据了它会对最终结果产生干扰,你从右边手套里拿手套就有可能拿到这些废数据,因此就不能够保证你一定能够选出一双颜色相同的手套,因此我们还需要记录一下另一边手套数不为0的废数据。
下面再来解释一下为什么要记录左右手套的总数以及左右边手套颜色最少的手套个数:当我们已经记录的废数据的情况下,我们如何才能够在拿手套数最少的前提下保证我们一定能够选出一双颜色相同的手套呢?我们是不是只需要把左手或者右手手套所有颜色的手套都拿过,然后再在再在另外一边手套中任意拿一个手套就可以了呢?是的。
那么现在我们的问题变成了:如何以最少的数量拿到单只手的所有颜色的手套。大家想一想我们是不是只需要拿这只手手套数的总和 - 这只手手套中颜色数最少的手套个数+1就可以了呢?
是的,如此一来我们就能以最少的数量拿到单只手的所有颜色的手套。
问题又来了:你这只是以最少数量拿到单只手的所有颜色的手套,那我们想以最少的数量拿到一双颜色相同的手套,是不是只需要取左手和右手以最少数量拿到单只手的所有颜色的手套的值中的最小值+废数据+1即可。
代码实现:
class Gloves {
public:
int findMinimum(int n, vector<int> left, vector<int> right) {
//记录最终答案
int ans = 0;
//记录左边手套的总数目
int left_sum = 0;
//记录左边手套颜色最少的手套
int left_min = INT_MAX;
//记录右边手套的总数目
int right_sum = 0;
//记录右边手套颜色最少的手套
int right_min = INT_MAX;
//记录一边手套数为0,另一边手套数不为0的废数据
int zero = 0;
for(int i = 0;i<n;i++)
{
//统计废数据的个数
if(left[i]*right[i]==0)
{
zero+=left[i]+right[i];
}
else
{
left_sum+=left[i];
//找出左边手套颜色最少的手套个数
left_min = min(left[i],left_min);
right_sum+=right[i];
//找出右边手套颜色最少的手套个数
right_min = min(right[i],right_min);
}
}
//我们想拿到左边或者右边手套中所有颜色的手套的最坏情况为:
//左边或者右边手套的总数 - 左边或者右边手套颜色最少的手套个数 +1
int ret = min(left_sum-left_min+1,right_sum-right_min+1);
//最后的答案我们还需要加上zero,因为一旦一边手套的数目为0,那么对应另一边的手套的数目就是废数据了
//最后我们只需要再在另一边再那一次 就能得到最少拿取一对颜色的手套的次数
ans = ret+zero+1;
return ans;
}
};