题目:
给你一个正整数数组 skill ,数组长度为 偶数 n ,其中 skill[i] 表示第 i 个玩家的技能点。将所有玩家分成 n / 2 个 2 人团队,使每一个团队的技能点之和 相等 。
团队的 化学反应 等于团队中玩家的技能点 乘积 。
返回所有团队的 化学反应 之和,如果无法使每个团队的技能点之和相等,则返回 -1 。
示例 1:
输入:skill = [3,2,5,1,3,4]
输出:22
解释:
将玩家分成 3 个团队 (1, 5), (2, 4), (3, 3) ,每个团队的技能点之和都是 6 。
所有团队的化学反应之和是 1 * 5 + 2 * 4 + 3 * 3 = 5 + 8 + 9 = 22 。
示例 2:
输入:skill = [3,4]
输出:12
解释:
两个玩家形成一个团队,技能点之和是 7 。
团队的化学反应是 3 * 4 = 12 。
示例 3:
输入:skill = [1,1,2,3]
输出:-1
解释:
无法将玩家分成每个团队技能点都相等的若干个 2 人团队。
提示:
2 <= skill.length <= 105
skill.length 是偶数
1 <= skill[i] <= 1000
题解:
方法一:
通过研究我们可以想到当数组(前提是有序)首尾元素配对时获得每队数据相加都相同的几率最大。第一个数和最后一个数配对,第二个和倒数第二个等等。现将数据排序,再求和sum,用sum/配对的个数即length/2就是配对后的两数相加的值。判断首尾元素相加是否等于sum/(length/2)
public long dividePlayers(int[] skill) {
int len=skill.length;
long sum=0;
if(len==2){
return skill[0]*skill[1];
}
Arrays.sort(skill);
for(int i=0;i<len;i++){
sum+=skill[i];
}
if(sum%(len/2)!=0){
return -1;
}
int r=0;
int l=len-1;
long sum1=0;
int num=(int)(sum/(len/2));
while (r<l){
if(skill[r]+skill[l]==num){
sum1+=skill[r]*skill[l];
r++;
l--;
}
else {
return -1;
}
}
return sum1;
}
方法二:
运用hash表。
用哈希表hash记录每个数字出现的次数,求出所有元素的和sum,用sum/(length/2)得出符合题意的团队的和num(num必为整数否则1返回-1)。如果hash[num-x]==0及与x配对的值不存在则取出x当hash[num-x]存在是时,把x*(num-x)加到答案ans中,然后判断参与计算的数字是否刚好为数组长度 ,最后返回答案的一半。
class Solution {
public long dividePlayers(int[] skill) {
var map = new HashMap<Long,Integer>();
long sum = 0;
int l = skill.length;
for(int item:skill){
sum+=item;
}
if(sum%(l/2)!=0){
return -1;
}
long num = sum/(l/2);
long ans = 0;
long count = 0;
for(long item:skill){
int temp = map.getOrDefault(num-item,0);
if(temp != 0){
count+=2;
ans+=(num-item)*item;
map.put(num-item,temp-1);
}else{
map.put( item,map.getOrDefault(item,0)+1);
}
}
//判断参与计算的数字是否刚好为数组长度,否则返回-1
return count == l? ans:-1;
}
}