数组 - 825. 适龄的朋友
人们会互相发送好友请求,现在给定一个包含有他们年龄的数组,
ages[i]
表示第 i 个人的年龄。当满足以下条件时,A 不能给 B(A、B不为同一人)发送好友请求:
age[B] <= 0.5 * age[A] + 7
age[B] > age[A]
age[B] > 100 && age[A] < 100
否则,A 可以给 B 发送好友请求。
注意如果 A 向 B 发出了请求,不等于 B 也一定会向 A 发出请求。而且,人们不会给自己发送好友请求。
求总共会发出多少份好友请求?
示例 1:
输入: [16,16] 输出: 2 解释: 二人可以互发好友申请。
示例 2:
输入: [16,17,18] 输出: 2 解释: 好友请求可产生于 17 -> 16, 18 -> 17.
示例 3:
输入: [20,30,100,110,120] 输出: 3 解释: 好友请求可产生于 110 -> 100, 120 -> 110, 120 -> 100
说明:
1 <= ages.length <= 20000. 1 <= ages[i] <= 120.
一.实现思路
本题为
循环比较
一类问题提供更优效率的思路
即:如何使循环比较
效率更高
由题可得:
扫描二维码关注公众号,回复:
10880717 查看本文章
age[B] > 0.5 * age[A] + 7
2 * age[B] > age[A] + 14age[B] > age[A] - age[B] + 14
应为 age[A] > age[B] ——> age[A] -age[B] > 0
所以最小值 age[B] > 14
去重方式
- 创建一个年龄数组,记录每个年龄出现的次数 counts
- 循环一次,去重放入集合 integers,并将年龄计数放入年龄数组
- 将 integeres 排序。循环集合,进行比较
- 同一个数之间的关系:由于n个数字之间的可能组合为
n * n-1
,所以count += counts[integers.get(i)] * (counts[integers.get(i)]-1)
- 不同数之间的关系:
count += counts[a]*counts[b];
- 同一个数之间的关系:由于n个数字之间的可能组合为
通过年龄数组循环方式(更优)
- 创建年龄数组,记录每个年龄出现的次数
- 这个情况下,就相当于已经去重了,直接循环这个年龄数组,如果
count[i]
的值不为null
则说明有,否则没有 - 循环判断,没有的情况直接
continue
- 剩下的和之前相同,这里判断的时候用到了一个右移,
和2相关的乘法除法都可以使用这个,增加效率
三.代码实现
去重方式
public class Solution {
int count = 0;
public int numFriendRequests(int[] ages) {
int[] counts = new int[121];
ArrayList<Integer> integers = new ArrayList<>();
for (int i = 0; i < ages.length; i++) {
if (counts[ages[i]]==0){
integers.add(ages[i]);
}
counts[ages[i]]++;
}
Collections.sort(integers);
for (int i = integers.size()-1; i >= 0; i--) {
if (integers.get(i)<15){
break;
}
if (counts[integers.get(i)]!=1){
count += counts[integers.get(i)] * (counts[integers.get(i)]-1);
}
for (int j = i - 1; j >= 0; j--) {
int a = integers.get(i);
int b = integers.get(j);
if (a / 2 + 7 >= b){
break;
}
if (a / 2 + 7 < b ) {
count += counts[a]*counts[b];
}
}
}
return count;
}
}
通过年龄数组循环方式(更优)
class Solution {
public int numFriendRequests(int[] ages) {
// 注意题目说的三个条件是满足其一就不能发!!!
int[] count = new int[121];
// 统计每个年龄的人的个数
for(int age : ages)
count[age]++;
int result = 0;
for(int i = 0; i <= 120; i++){
// 该年龄没有人的,直接跳过
if(count[i] == 0)
continue;
// 这里是针对同龄人的情况,设当前年龄为i
// 对于同龄人,第2,3个条件均不满足,只考虑第一个条件
// 对于第1个条件,可以发送的情况是:i > 0.5 * i + 7
// 简单化简即可得到下述判断条件,注意排除和自己发消息的情况
if(i > 14)
result += count[i] * (count[i] - 1);
// 不同年龄的人,假设当前人为A,分析三个条件可知,另一个人B的年龄:
// 1. ageB > 0.5 * ageA + 7
// 2. 要小于A(等于的情况计算过了)
// 3. 可以划入2
// 这里在循环条件中控制了1,内层判断2.对于满足条件的,每个i可以给所有j发,所以是count[i] * count[j]
for(int j = 0; j < i; j++){
if(j > (i >>> 1) + 7){
result += count[i] * count[j];
}
}
}
return result;
}
}