Facebook Pixel

825. Friends Of Appropriate Ages

Problem Description

You are given an array ages representing the ages of n people on a social media website. You need to determine the total number of friend requests that will be made based on specific rules.

A person x will send a friend request to person y (where x != y) only if ALL of the following conditions are false:

  • age[y] <= 0.5 * age[x] + 7
  • age[y] > age[x]
  • age[y] > 100 && age[x] < 100

In other words, person x will send a request to person y if:

  • age[y] > 0.5 * age[x] + 7 AND
  • age[y] <= age[x] AND
  • NOT (age[y] > 100 && age[x] < 100)

Important notes:

  • Friend requests are one-directional. If x sends a request to y, it doesn't mean y will send a request back to x.
  • A person cannot send a friend request to themselves.
  • You need to count all possible friend requests that will be made across all people.

For example, if person A (age 16) and person B (age 15) exist:

  • Person A checks if they can send to B: 15 > 0.5 * 16 + 7 = 15? No, so A won't send to B.
  • Person B checks if they can send to A: 16 > 0.5 * 15 + 7 = 14.5? Yes. 16 <= 15? No, so B won't send to A.

The solution uses a counting approach where it tracks the frequency of each age (since ages are limited to 1-120), then checks all possible age pairs to calculate the total number of friend requests based on the given conditions.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is that we don't need to check every individual person against every other person, which would be O(n²). Instead, we can group people by their ages since the friend request rules only depend on ages, not on individual identities.

Think about it this way: if there are 5 people aged 20 and 3 people aged 18, any person aged 20 will have the same relationship with any person aged 18 based on the rules. So instead of checking 5 × 3 = 15 individual pairs, we can check the age pair (20, 18) once and multiply by the counts.

Since ages are limited to a small range (1-120), we can use a frequency array cnt where cnt[age] represents how many people have that specific age. This transforms our problem from "checking n people" to "checking at most 121 distinct ages".

For each age pair (ax, ay):

  • If the ages satisfy the friend request conditions, we know that every person of age ax will send a request to every person of age ay
  • If ax == ay (same age group), each person sends requests to others in the same group, giving us cnt[ax] * (cnt[ax] - 1) requests (subtract 1 because you can't send to yourself)
  • If ax != ay (different ages), we get cnt[ax] * cnt[ay] requests

This reduces the time complexity from O(n²) to O(121²), which is effectively O(1) since 121 is a constant. The space-time tradeoff of using a counting array makes the solution much more efficient when dealing with many people but limited age values.

Learn more about Two Pointers, Binary Search and Sorting patterns.

Solution Approach

The implementation uses a counting approach with enumeration to efficiently solve the problem.

Step 1: Count the frequency of each age

We create a frequency array cnt of size 121 (to cover ages 0-120):

cnt = [0] * 121
for x in ages:
    cnt[x] += 1

This allows us to group people by their ages, where cnt[i] represents the number of people with age i.

Step 2: Enumerate all possible age pairs

We iterate through all possible combinations of ages using nested loops:

for ax, x in enumerate(cnt):
    for ay, y in enumerate(cnt):

Here:

  • ax and ay represent the ages being compared
  • x and y represent the count of people with ages ax and ay respectively

Step 3: Check friend request conditions

For each age pair (ax, ay), we check if person of age ax can send a friend request to person of age ay. The condition for sending a request is the negation of the three blocking conditions:

if not (ay <= 0.5 * ax + 7 or ay > ax or (ay > 100 and ax < 100)):

Step 4: Calculate the number of friend requests

If the conditions are satisfied:

  • When ax == ay (same age): Each person sends requests to all others in the same age group except themselves, contributing x * (x - 1) requests
  • When ax != ay (different ages): Each person of age ax sends to each person of age ay, contributing x * y requests

This is handled by the formula:

ans += x * (y - int(ax == ay))

The expression (y - int(ax == ay)) elegantly handles both cases:

  • If ax == ay, it becomes y - 1, accounting for not sending to oneself
  • If ax != ay, it remains y

Time Complexity: O(121²) = O(1) since we iterate through a fixed range of ages
Space Complexity: O(121) = O(1) for the counting array

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a small example with ages = [16, 16, 16, 17, 19].

Step 1: Build frequency array First, we count how many people have each age:

  • Age 16: 3 people
  • Age 17: 1 person
  • Age 19: 1 person
  • All other ages: 0 people

So cnt[16] = 3, cnt[17] = 1, cnt[19] = 1, and all other entries are 0.

Step 2: Check all age pairs

Now we check each non-zero age pair to see if friend requests can be made:

Age 16 → Age 16:

  • Check conditions: 16 > 0.5 * 16 + 7 = 15? Yes ✓
  • 16 <= 16? Yes ✓
  • Not (16 > 100 && 16 < 100)? Yes ✓
  • All conditions pass! Each 16-year-old sends to other 16-year-olds
  • Requests: 3 * (3 - 1) = 6 (each of 3 people sends to 2 others)

Age 16 → Age 17:

  • Check: 17 > 0.5 * 16 + 7 = 15? Yes ✓
  • 17 <= 16? No ✗
  • Conditions fail, no requests

Age 17 → Age 16:

  • Check: 16 > 0.5 * 17 + 7 = 15.5? Yes ✓
  • 16 <= 17? Yes ✓
  • Not (16 > 100 && 17 < 100)? Yes ✓
  • All conditions pass!
  • Requests: 1 * 3 = 3 (the one 17-year-old sends to all three 16-year-olds)

Age 19 → Age 16:

  • Check: 16 > 0.5 * 19 + 7 = 16.5? No ✗
  • Conditions fail, no requests

Age 19 → Age 17:

  • Check: 17 > 0.5 * 19 + 7 = 16.5? Yes ✓
  • 17 <= 19? Yes ✓
  • Not (17 > 100 && 19 < 100)? Yes ✓
  • All conditions pass!
  • Requests: 1 * 1 = 1 (the 19-year-old sends to the 17-year-old)

Step 3: Sum up all requests Total friend requests = 6 + 3 + 1 = 10

The key insight is that instead of checking all 5 × 4 = 20 person-to-person combinations, we only checked the unique age pairs and multiplied by their frequencies, making the solution much more efficient.

Solution Implementation

1from typing import List
2
3class Solution:
4    def numFriendRequests(self, ages: List[int]) -> int:
5        # Count frequency of each age (ages range from 1 to 120)
6        age_count = [0] * 121
7        for age in ages:
8            age_count[age] += 1
9      
10        total_requests = 0
11      
12        # Check all possible age pairs
13        for age_x in range(121):
14            if age_count[age_x] == 0:
15                continue
16              
17            for age_y in range(121):
18                if age_count[age_y] == 0:
19                    continue
20              
21                # Friend request conditions (person x will NOT send request to y if):
22                # 1. age_y <= 0.5 * age_x + 7
23                # 2. age_y > age_x
24                # 3. age_y > 100 and age_x < 100
25                if age_y <= 0.5 * age_x + 7:
26                    continue
27                if age_y > age_x:
28                    continue
29                if age_y > 100 and age_x < 100:
30                    continue
31              
32                # Valid friend request scenario
33                if age_x == age_y:
34                    # Same age: each person can send to others of same age (excluding themselves)
35                    total_requests += age_count[age_x] * (age_count[age_y] - 1)
36                else:
37                    # Different ages: all people of age_x can send to all people of age_y
38                    total_requests += age_count[age_x] * age_count[age_y]
39      
40        return total_requests
41
1class Solution {
2    public int numFriendRequests(int[] ages) {
3        // Maximum age is 120, so we create an array of size 121 (0-120)
4        final int MAX_AGE = 121;
5        int[] ageCount = new int[MAX_AGE];
6      
7        // Count the frequency of each age
8        for (int age : ages) {
9            ageCount[age]++;
10        }
11      
12        int totalRequests = 0;
13      
14        // Iterate through all possible age combinations
15        for (int ageX = 1; ageX < MAX_AGE; ageX++) {
16            for (int ageY = 1; ageY < MAX_AGE; ageY++) {
17                // Check if person X (with ageX) can send friend request to person Y (with ageY)
18                // Person X will NOT send a friend request to person Y if any of the following is true:
19                // 1. ageY <= 0.5 * ageX + 7
20                // 2. ageY > ageX
21                // 3. ageY > 100 && ageX < 100
22                boolean condition1 = ageY <= 0.5 * ageX + 7;
23                boolean condition2 = ageY > ageX;
24                boolean condition3 = ageY > 100 && ageX < 100;
25              
26                if (!condition1 && !condition2 && !condition3) {
27                    // Calculate the number of friend requests
28                    // If ageX equals ageY, we need to subtract 1 to avoid self-request
29                    int requestsFromXToY = ageCount[ageX] * ageCount[ageY];
30                    if (ageX == ageY) {
31                        // When ages are the same, subtract the diagonal (self-requests)
32                        requestsFromXToY = ageCount[ageX] * (ageCount[ageY] - 1);
33                    }
34                    totalRequests += requestsFromXToY;
35                }
36            }
37        }
38      
39        return totalRequests;
40    }
41}
42
1class Solution {
2public:
3    int numFriendRequests(vector<int>& ages) {
4        // Maximum age is 120, so we create a frequency array of size 121 (0-120)
5        const int MAX_AGE = 121;
6        vector<int> ageCount(MAX_AGE);
7      
8        // Count the frequency of each age
9        for (int age : ages) {
10            ++ageCount[age];
11        }
12      
13        int totalRequests = 0;
14      
15        // Check all possible age pairs
16        for (int ageX = 1; ageX < MAX_AGE; ++ageX) {
17            for (int ageY = 1; ageY < MAX_AGE; ++ageY) {
18                // Check if person X (with ageX) can send friend request to person Y (with ageY)
19                // Person X will NOT send a friend request to person Y if any of the following is true:
20                // 1. ageY <= 0.5 * ageX + 7
21                // 2. ageY > ageX
22                // 3. ageY > 100 && ageX < 100
23              
24                bool condition1 = ageY <= 0.5 * ageX + 7;
25                bool condition2 = ageY > ageX;
26                bool condition3 = ageY > 100 && ageX < 100;
27              
28                // If none of the conditions are true, X can send request to Y
29                if (!condition1 && !condition2 && !condition3) {
30                    // Calculate the number of friend requests
31                    // Each person with ageX can send requests to all people with ageY
32                    if (ageX == ageY) {
33                        // If ages are the same, each person can send to others but not themselves
34                        // So we subtract 1 from the count for self-request
35                        totalRequests += ageCount[ageX] * (ageCount[ageY] - 1);
36                    } else {
37                        // Different ages: all people with ageX can send to all people with ageY
38                        totalRequests += ageCount[ageX] * ageCount[ageY];
39                    }
40                }
41            }
42        }
43      
44        return totalRequests;
45    }
46};
47
1/**
2 * Calculates the total number of friend requests that will be made based on ages.
3 * A person x will send a friend request to person y if:
4 * - y > 0.5 * x + 7
5 * - y <= x
6 * - !(y > 100 && x < 100)
7 * 
8 * @param ages - Array of ages of people
9 * @returns Total number of friend requests that will be made
10 */
11function numFriendRequests(ages: number[]): number {
12    // Maximum age is 120, so we use 121 to include index 120
13    const MAX_AGE: number = 121;
14  
15    // Count frequency of each age
16    const ageCount: number[] = Array(MAX_AGE).fill(0);
17    for (const age of ages) {
18        ageCount[age]++;
19    }
20
21    let totalRequests: number = 0;
22  
23    // Check all possible age combinations
24    for (let ageX: number = 0; ageX < MAX_AGE; ageX++) {
25        for (let ageY: number = 0; ageY < MAX_AGE; ageY++) {
26            // Check if person with ageX will NOT send request to person with ageY
27            if (ageY <= 0.5 * ageX + 7 || ageY > ageX || (ageY > 100 && ageX < 100)) {
28                continue;
29            }
30          
31            // Calculate number of requests from people of ageX to people of ageY
32            // If ageX equals ageY, subtract 1 to avoid self-requests
33            const requestCount: number = ageCount[ageX] * (ageCount[ageY] - (ageX === ageY ? 1 : 0));
34            totalRequests += requestCount;
35        }
36    }
37
38    return totalRequests;
39}
40

Time and Space Complexity

Time Complexity: O(n + m²), where n is the length of the array ages and m is the maximum possible age value (121 in this problem).

  • The first loop iterates through all n elements in the ages array to count the frequency of each age, contributing O(n).
  • The nested loops iterate through all possible age pairs, where both loops run from 0 to 120 (inclusive), resulting in O(m²) = O(121²) iterations.
  • Inside the nested loops, all operations (condition checking and arithmetic) are O(1).
  • Therefore, the total time complexity is O(n + m²).

Space Complexity: O(m), where m is the maximum possible age value (121).

  • The cnt array has a fixed size of 121 elements regardless of the input size, requiring O(121) = O(m) space.
  • All other variables (ans, ax, ay, x, y) use constant space O(1).
  • Therefore, the total space complexity is O(m).

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Misunderstanding the Friend Request Logic

Pitfall: The most common mistake is misinterpreting the condition logic. The problem states that person x will send a request if ALL three conditions are FALSE. Many developers incorrectly implement this as checking if ANY condition is true to block the request.

Incorrect Implementation:

# Wrong: Using OR logic when we need AND logic for blocking
if ay <= 0.5 * ax + 7 or ay > ax or (ay > 100 and ax < 100):
    continue  # Skip if ANY condition blocks the request

Correct Understanding: The request is sent when ALL blocking conditions are false, which means we need to check the negation of each condition. The request happens when:

  • age_y > 0.5 * age_x + 7 (NOT less than or equal)
  • age_y <= age_x (NOT greater than)
  • NOT (age_y > 100 AND age_x < 100)

2. Handling Same-Age Friend Requests Incorrectly

Pitfall: When two people have the same age, forgetting that a person cannot send a friend request to themselves leads to overcounting.

Incorrect Implementation:

if age_x == age_y:
    # Wrong: This counts self-requests
    total_requests += age_count[age_x] * age_count[age_y]

Correct Implementation:

if age_x == age_y:
    # Correct: Subtract 1 to exclude self-requests
    total_requests += age_count[age_x] * (age_count[age_y] - 1)

3. Double-Counting Friend Requests

Pitfall: Some developers mistakenly think they need to divide the result by 2, assuming bidirectional counting.

Why This is Wrong: Friend requests are directional. If person A can send to person B, it doesn't mean B can send to A. Each valid request should be counted exactly once. The algorithm already handles this correctly by checking each ordered pair (x, y) separately.

4. Inefficient Brute Force Implementation

Pitfall: Implementing a naive O(n²) solution that compares every person with every other person directly.

Inefficient Approach:

def numFriendRequests(self, ages: List[int]) -> int:
    n = len(ages)
    total = 0
    for i in range(n):
        for j in range(n):
            if i != j:
                # Check conditions for ages[i] sending to ages[j]
                if ages[j] > 0.5 * ages[i] + 7 and ages[j] <= ages[i]:
                    if not (ages[j] > 100 and ages[i] < 100):
                        total += 1
    return total

Better Solution: Use the counting approach shown in the original solution, which groups people by age and processes age pairs rather than individual pairs, reducing time complexity when many people share the same age.

5. Edge Case: Very Young Ages

Pitfall: Not recognizing that very young ages (typically under 15) cannot send friend requests to anyone due to the 0.5 * age + 7 condition.

Example: For age 14: 0.5 * 14 + 7 = 14, meaning they can only send requests to people older than 14, but the second condition requires age_y <= 14. These constraints are contradictory, so age 14 cannot send any requests.

Solution: The algorithm handles this naturally, but understanding this helps with debugging and test case creation. You can add an optimization to skip processing ages below 15 as senders:

for age_x in range(15, 121):  # Start from 15 instead of 0
    if age_count[age_x] == 0:
        continue
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Given a sorted array of integers and an integer called target, find the element that equals to the target and return its index. Select the correct code that fills the ___ in the given code snippet.

1def binary_search(arr, target):
2    left, right = 0, len(arr) - 1
3    while left ___ right:
4        mid = (left + right) // 2
5        if arr[mid] == target:
6            return mid
7        if arr[mid] < target:
8            ___ = mid + 1
9        else:
10            ___ = mid - 1
11    return -1
12
1public static int binarySearch(int[] arr, int target) {
2    int left = 0;
3    int right = arr.length - 1;
4
5    while (left ___ right) {
6        int mid = left + (right - left) / 2;
7        if (arr[mid] == target) return mid;
8        if (arr[mid] < target) {
9            ___ = mid + 1;
10        } else {
11            ___ = mid - 1;
12        }
13    }
14    return -1;
15}
16
1function binarySearch(arr, target) {
2    let left = 0;
3    let right = arr.length - 1;
4
5    while (left ___ right) {
6        let mid = left + Math.trunc((right - left) / 2);
7        if (arr[mid] == target) return mid;
8        if (arr[mid] < target) {
9            ___ = mid + 1;
10        } else {
11            ___ = mid - 1;
12        }
13    }
14    return -1;
15}
16

Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More