数组 - [825. 适龄的朋友]

数组 - 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

去重方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zZmUuMzc-1578881092110)(en-resource://database/8697:0)]

  1. 创建一个年龄数组,记录每个年龄出现的次数 counts
  2. 循环一次,去重放入集合 integers,并将年龄计数放入年龄数组
  3. 将 integeres 排序。循环集合,进行比较
    1. 同一个数之间的关系:由于n个数字之间的可能组合为 n * n-1 ,所以 count += counts[integers.get(i)] * (counts[integers.get(i)]-1)
    2. 不同数之间的关系:count += counts[a]*counts[b];

通过年龄数组循环方式(更优)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QxOksUNT-1578881092132)(en-resource://database/8695:0)]

  1. 创建年龄数组,记录每个年龄出现的次数
  2. 这个情况下,就相当于已经去重了,直接循环这个年龄数组,如果 count[i] 的值 不为null 则说明有,否则没有
  3. 循环判断,没有的情况直接 continue
  4. 剩下的和之前相同,这里判断的时候用到了一个右移,和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;
    }
}


发布了96 篇原创文章 · 获赞 26 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq919694688/article/details/103953159