持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情
题目描述
在社交媒体网站上有 n 个用户。给你一个整数数组 ages ,其中 ages[i] 是第 i 个用户的年龄。
如果下述任意一个条件为真,那么用户 x 将不会向用户 y(x != y)发送好友请求:
ages[y] <= 0.5 * ages[x] + 7
ages[y] > ages[x]
ages[y] > 100 && ages[x] < 100
否则,x 将会向 y 发送一条好友请求。
注意,如果 x 向 y 发送一条好友请求,y 不必也向 x 发送一条好友请求。另外,用户不会向自己发送好友请求。
返回在该社交媒体网站上产生的好友请求总数。
示例 1:
输入:ages = [16,16] 输出:2 解释:2 人互发好友请求。
示例2
输入:ages = [16,17,18] 输出:2 解释:产生的好友请求为 17 -> 16 ,18 -> 17 。
桶计数
思路分析:从里面可以分析出来n <= 2 * 10^4,如果我们使用O(n^2)肯定就吃TE了,所以得优化时间复杂度,分析题目发现我们可以剪枝,以下条件时成立时,就不会出现用户 x 向用户 y(x != y)发送好友请求。
- age[y] <= 0.5 * age[x] + 7
- age[y] > age[x] age[y] > 100
- && age[x] < 100
那么可以吧这些无效的重复的操作直接省略掉,再利用桶来计数,那么就可以大幅度降低时间复杂度。桶计数的具体步骤如下:
- 首先创建两个数组,将计数数组ageCnt和累加计数数组ageSum,分别用来统计某年龄的人数和小于等于此年龄的人数。
- 然后将ages中的age计次,放入ageCnt数组。计算小于等于年龄i的人数,放入数组ageSum。利用循环,计算对于每个年龄i会发送好友请求的人数,其中选择范围为(i*0.5+7 -- i),同时去掉自己,并乘以此年龄的人数。累加到答案res中。
class Solution {
public int minSwapsCouples(int[] row) {
int n = row.length/2;
Union u = new Union(n);
for(int i = 0; i < n; i++){
u.connect(row[i*2]/2,row[i*2+1]/2);
}
return u.getPart();
}
class Union{
int[] parent;
int[] sizes;
int total;
public Union(int n){
parent = new int[n];
for(int i = 0; i < n; i++){
parent[i] = i;
}
sizes = new int[n];
Arrays.fill(sizes,1);
total = n;
}
public int getPart(){
return sizes.length-total;
}
public void connect(int a, int b){
int rootA = root(a);
int rootB = root(b);
if(rootA==rootB) return;
if(sizes[rootA]>=sizes[rootB]){
sizes[rootA]+=sizes[rootB];
parent[rootB] = rootA;
}else{
sizes[rootB]+=sizes[rootA];
parent[rootA] = rootB;
}
--total;
}
private int root(int a){
while(parent[a]!=a){
parent[a] = root(parent[a]);
a = parent[a];
}
return a;
}
}
}
最后
题目感觉有点绕,有几点要注意才行:
- 年龄相等也可以给同龄人发送请求
- 15岁以下不能交友