leetcode
leetcode 701 ~ 750
适龄的朋友

适龄的朋友

难度:

标签:

题目描述

代码结果

运行时间: 40 ms, 内存: 16.8 MB


/*
 * 思路:
 * 使用Java Streams来简化迭代过程。我们可以利用流的特性来实现对每一对用户进行检查。
 */

import java.util.Arrays;

public class FriendRequestsStream {
    public long numFriendRequests(int[] ages) {
        return Arrays.stream(ages)
                .boxed()
                .flatMap(ageX -> Arrays.stream(ages)
                        .filter(ageY -> ageX != ageY && canSendRequest(ageX, ageY)))
                .count();
    }

    private boolean canSendRequest(int ageX, int ageY) {
        if (ageY <= 0.5 * ageX + 7) return false;
        if (ageY > ageX) return false;
        if (ageY > 100 && ageX < 100) return false;
        return true;
    }
}

解释

方法:

This solution utilizes a frequency array to count the occurrences of each age from 1 to 120. It creates a prefix sum array to quickly calculate the sum of frequencies up to any given age. The logic involves iterating over each age and determining the range of ages that can receive friend requests from that age based on the given conditions. For each valid age, the solution calculates the number of potential friend requests by multiplying the frequency of the current age by the number of users in the valid age range (using the prefix sum to find this number quickly). This method avoids the need for nested iterations over the `ages` array, thus improving efficiency.

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
如何确定边界条件`ages[y] <= 0.5 * ages[x] + 7`的最小有效年龄`y`?
在这个条件下,我们需要计算能发送好友请求的最小年龄`y`。根据条件`ages[y] <= 0.5 * ages[x] + 7`,我们将`y`设为`0.5 * i + 7`的最大整数值。为了确保`y`是有效的,我们使用向下取整的方式(因为年龄为整数),即`y = floor(0.5 * i + 7)`。例如,如果`i`为20,那么`0.5 * 20 + 7 = 17`,有效的最小`y`就是18(因为17是不包括在内的),所以我们从18岁开始计算能接受的好友请求。
🦆
为什么在计算可能的好友请求时,要使用`pref_sum[i] - pref_sum[val] - 1`来计算年龄`i`可以发送请求的用户数?
这里的`pref_sum`数组是年龄的累积频数,即`pref_sum[i]`表示从1岁到`i`岁的用户总数。`val`是根据`0.5 * i + 7`规则计算得到的最小年龄。`pref_sum[i] - pref_sum[val]`计算的是年龄在`(val, i]`范围内的用户数。由于年龄为`i`的用户不能向自己发送好友请求,所以需要再减去1,即`-1`部分。这样,`pref_sum[i] - pref_sum[val] - 1`就准确地表示了年龄为`i`的用户可以发送的好友请求数量。
🦆
在计算前缀和数组`pref_sum`时,为什么`pref_sum[i]`的计算可以直接依赖`pref_sum[i-1]`而不需要额外的循环?
`pref_sum`数组是一个累积和数组,其中`pref_sum[i]`表示从1岁到`i`岁所有年龄的用户总数。每个`pref_sum[i]`可以通过`pref_sum[i-1]`(即前一个年龄的累积和)加上当前年龄`i`的用户数`ages_count[i]`计算得到。这样,每次计算只需要当前和前一个元素的值,因此不需要额外的循环。这是因为前缀和的性质使得每个元素的计算仅依赖于其前一个元素,从而实现了高效的累计计算。
🦆
题解中提到的优化避免了嵌套迭代,这种方法具体是如何通过前缀和数组减少计算次数的?
在没有前缀和数组的情况下,我们可能需要对每个年龄`i`,遍历所有可能的年龄`y`来检查是否满足好友请求的条件,这就需要嵌套迭代。通过使用前缀和数组,我们可以直接通过`pref_sum`快速计算在任意年龄范围内的用户数,从而避免了对每个年龄进行二次迭代的需要。例如,对于每个年龄`i`,通过一次查找就可以得到范围内的用户总数,大大减少了总体的计算次数,提高了算法的效率。

相关问题