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
ANDage[y] <= age[x]
AND- NOT (
age[y] > 100 && age[x] < 100
)
Important notes:
- Friend requests are one-directional. If
x
sends a request toy
, it doesn't meany
will send a request back tox
. - 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.
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 ageay
- If
ax == ay
(same age group), each person sends requests to others in the same group, giving uscnt[ax] * (cnt[ax] - 1)
requests (subtract 1 because you can't send to yourself) - If
ax != ay
(different ages), we getcnt[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
anday
represent the ages being comparedx
andy
represent the count of people with agesax
anday
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, contributingx * (x - 1)
requests - When
ax != ay
(different ages): Each person of ageax
sends to each person of ageay
, contributingx * 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 becomesy - 1
, accounting for not sending to oneself - If
ax != ay
, it remainsy
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 EvaluatorExample 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 theages
array to count the frequency of each age, contributingO(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, requiringO(121) = O(m)
space. - All other variables (
ans
,ax
,ay
,x
,y
) use constant spaceO(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
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
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Binary Search Speedrun For each of the Speedrun questions you will be given a binary search related problem and a corresponding multiple choice question The multiple choice questions are related to the techniques and template s introduced in the binary search section It's recommended that you have gone through at
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Want a Structured Path to Master System Design Too? Don’t Miss This!