Number of Distinct Averages solution and explanation
9 more videos on this problem
Leetcode | 2465. Number of Distinct Averages | Easy | Java SolutionDeveloper Docs · 5:35 · 905 views
2465. Number of Distinct Averages | LEETCODE EASYcode Explainer · 3:19 · 544 views
2465. Number of Distinct Averages (Leetcode Easy)Programming Live with Larry · 3:09 · 401 views
LeetCode 2465 – Distinct Averages Explained 🔥 | Java Interview PrepRecurso · 11:03 · 222 views
Leetcode BiWeekly contest 91 - Easy - Number of Distinct AveragesPrakhar Agrawal · 3:13 · 186 views
Leetcode 2465. Number of Distinct AveragesElite Code · 9:01 · 156 views
Day 22 – Two Pointer Technique | LeetCode 2465: Number of Distinct Averages 🚀 #leetcode#coding#tamilAbinaya · 7:17 · 137 views
Number of Distinct Averages | Leetcode 2465 | Approach + Code with explanation.Pirai's Academy · 10:35 · 113 views
2465. Number Of Distinct Averages||Leetcode biweekly contest91||Code belowCS warriors · 6:42 · 90 views
2465. Number of Distinct Averages Leetcode || Java || #Biweekly Contest 91 || #leetcodeThe Planet · 11:29 · 81 views
The problem
You are given a 0-indexed integer array nums of even length.
As long as nums is not empty, you must repetitively:
- Find the minimum number in
numsand remove it. - Find the maximum number in
numsand remove it. - Calculate the average of the two removed numbers.
The average of two numbers a and b is (a + b) / 2.
- For example, the average of
2and3is(2 + 3) / 2 = 2.5.
Return the number of distinct averages calculated using the above process.
Note that when there is a tie for a minimum or maximum number, any can be removed.
Example 1:
Input: nums = [4,1,4,0,3,5] Output: 2 Explanation: 1. Remove 0 and 5, and the average is (0 + 5) / 2 = 2.5. Now, nums = [4,1,4,3]. 2. Remove 1 and 4. The average is (1 + 4) / 2 = 2.5, and nums = [4,3]. 3. Remove 3 and 4, and the average is (3 + 4) / 2 = 3.5. Since there are 2 distinct numbers among 2.5, 2.5, and 3.5, we return 2.
Example 2:
Input: nums = [1,100] Output: 1 Explanation: There is only one average to be calculated after removing 1 and 100, so we return 1.
Constraints:
2 <= nums.length <= 100nums.lengthis even.0 <= nums[i] <= 100
Approach overview
Problem Overview: You are given an even-length integer array. In each step, remove the smallest and largest numbers, compute their average, and store it. Repeat until the array is empty. The goal is to return how many distinct averages appear during this process.
Approach 1: Using Hash Maps / Hash Set (O(n log n) time, O(n) space)
This approach focuses on tracking unique averages using a hash-based structure. First, sort the array so the smallest and largest values can be accessed easily. Then iterate using two pointers: one at the beginning and one at the end of the array. For every pair, compute the average using (nums[left] + nums[right]) / 2 and insert the result into a hash set. Because sets store only unique values, duplicates are automatically removed. Continue moving the pointers inward until all elements are processed.
The key idea is that the order of removal does not affect the result once the array is sorted. Every step always combines the smallest and largest remaining elements. The hash structure guarantees O(1) average insertion and lookup, so counting distinct averages becomes straightforward. This method works well for general hash table problems where uniqueness needs to be tracked efficiently.
Approach 2: Using Sorting and Two Pointers (O(n log n) time, O(n) space)
Another clean solution relies on sorting and the classic two-pointer technique. After sorting the array, place one pointer at the start and another at the end. Each iteration forms a pair consisting of the minimum and maximum remaining values. Compute their sum or average and store it in a set. Move the left pointer forward and the right pointer backward until they cross.
The sorting step dominates the runtime with O(n log n), while the pairing process itself runs in O(n). This approach highlights a common pattern in two pointers and sorting problems: sort first, then process symmetric elements from both ends. It avoids repeated scanning for minimum or maximum values and keeps the implementation compact.
Recommended for interviews: Interviewers usually expect the sorting + two-pointer solution. It demonstrates recognition of a symmetric pairing pattern and efficient iteration across the array. Mentioning a hash set to track unique averages shows awareness of constant-time lookups. A brute-force idea (repeatedly scanning for min and max) shows baseline understanding, but the sorted two-pointer solution shows stronger algorithmic thinking.
Approach 1: Approach 1: Using Hash Maps
This approach utilizes hash maps (or dictionaries) to store and efficiently query required data. The hash map data structure offers average constant time complexity for insertions and lookups, making it ideal for problems where we need to frequently access or update information.
hash_map = {}
# Insert key-value pairs
hash_map[1] = 100
hash_map[2] = 200
# Search for keys
print(f"Value for key 1: {hash_map.get(1, -1)}")
print(f"Value for key 2: {hash_map.get(2, -1)}")import java.util.HashMap;
public class Main {
public static void main(String[] args) {
HashMap<Integer, Integer> map = new HashMap<>();
// Insert key-value pairs
map.put(1, 100);
map.put(2, 200);
// Search for keys
System.out.println("Value for key 1: " + map.getOrDefault(1, -1));
System.out.println("Value for key 2: " + map.getOrDefault(2, -1));
}
}#include <iostream>
#include <unordered_map>
using namespace std;
int main() {
// Create an unordered_map
unordered_map<int, int> map;
// Insert key-value pairs
map[1] = 100;
map[2] = 200;
// Search for keys
cout << "Value for key 1: " << map[1] << endl;
cout << "Value for key 2: " << (map.count(2) ? map[2] : -1) << endl;
return 0;
}const map = new Map();
// Insert key-value pairs
map.set(1, 100);
map.set(2, 200);
// Search for keys
console.log(`Value for key 1: ${map.get(1) ?? -1}`);
console.log(`Value for key 2: ${map.get(2) ?? -1}`);#include <stdio.h>
#include <stdlib.h>
#define TABLE_SIZE 1000
// Define a structure for the hash table entries.
typedef struct entry {
int key;
int value;
struct entry *next;
} Entry;
Entry *hashTable[TABLE_SIZE];
unsigned int hashFunction(int key) {
return key % TABLE_SIZE;
}
void insert(int key, int value) {
unsigned int index = hashFunction(key);
Entry *newEntry = (Entry *)malloc(sizeof(Entry));
newEntry->key = key;
newEntry->value = value;
newEntry->next = hashTable[index];
hashTable[index] = newEntry;
}
int search(int key) {
unsigned int index = hashFunction(key);
Entry *entry = hashTable[index];
while (entry != NULL) {
if (entry->key == key) {
return entry->value;
}
entry = entry->next;
}
return -1; // Key not found
}
int main() {
// Initialize hash table
for (int i = 0; i < TABLE_SIZE; i++) {
hashTable[i] = NULL;
}
// Example usage
insert(1, 100);
insert(2, 200);
printf("Value for key 1: %d\n", search(1));
printf("Value for key 2: %d\n", search(2));
return 0;
}using System;
using System.Collections.Generic;
class Program {
static void Main() {
Dictionary<int, int> dict = new Dictionary<int, int>();
// Insert key-value pairs
dict[1] = 100;
dict[2] = 200;
// Search for keys
Console.WriteLine("Value for key 1: " + (dict.TryGetValue(1, out int value1) ? value1 : -1));
Console.WriteLine("Value for key 2: " + (dict.TryGetValue(2, out int value2) ? value2 : -1));
}
}This Python solution uses a dictionary, which is Python's built-in hash table implementation. Keys are inserted directly via the index assignment, and 'get' is used for safe retrieval with a default value.
Time Complexity: O(1) average for insert and search, O(n) in the worst case.
Space Complexity: O(n), where n is the number of entries in the dictionary.
Approach 2: Approach 2: Using Sorting and Binary Search
This approach involves first sorting the data, which allows us to use binary search for efficient lookups. Although this incurs a sorting overhead, it can be effective when dealing with static data where many lookups are needed and few or no updates.
import bisect
arr = [3, 2, 1, 5, 4]
arr.sort()
# Use bisect for binary search
x = 3
index = bisect.bisect_left(arr, x)
if index < len(arr) and arr[index] == x:
print(f"Element found at index {index}")
else:
print("Element not found")import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] arr = {3, 2, 1, 5, 4};
// Sort the array
Arrays.sort(arr);
// Use binary search
int x = 3;
int result = Arrays.binarySearch(arr, x);
if (result >= 0)
System.out.println("Element found at index " + result);
else
System.out.println("Element not found");
}
}#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int arr[] = {3, 2, 1, 5, 4};
int n = sizeof(arr) / sizeof(arr[0]);
// Sort the array
sort(arr, arr + n);
// Use binary search
int x = 3;
if (binary_search(arr, arr + n, x))
cout << "Element found." << endl;
else
cout << "Element not found." << endl;
return 0;
}const arr = [3, 2, 1, 5, 4];
arr.sort((a, b) => a - b);
const binarySearch = (arr, x) => {
let start = 0, end = arr.length - 1;
while (start <= end) {
let mid = Math.floor((start + end) / 2);
if (arr[mid] === x) return mid;
else if (arr[mid] < x) start = mid + 1;
else end = mid - 1;
}
return -1;
};
const x = 3;
const index = binarySearch(arr, x);
console.log(index !== -1 ? `Element found at index ${index}` : "Element not found");#include <stdio.h>
#include <stdlib.h>
int compare(const void * a, const void * b) {
return (*(int*)a - *(int*)b);
}
int binarySearch(int arr[], int size, int x) {
int l = 0, r = size - 1;
while (l <= r) {
int mid = l + (r - l) / 2;
if (arr[mid] == x)
return mid;
if (arr[mid] < x)
l = mid + 1;
else
r = mid - 1;
}
return -1;
}
int main() {
int arr[] = {3, 2, 1, 5, 4};
int n = sizeof(arr) / sizeof(arr[0]);
qsort(arr, n, sizeof(int), compare);
int x = 3;
int result = binarySearch(arr, n, x);
if (result != -1) printf("Element found at index %d\n", result);
else printf("Element not found\n");
return 0;
}using System;
class Program {
static void Main() {
int[] arr = {3, 2, 1, 5, 4};
Array.Sort(arr);
int x = 3;
int index = Array.BinarySearch(arr, x);
if (index >= 0)
Console.WriteLine($"Element found at index {index}");
else
Console.WriteLine("Element not found");
}
}This Python solution sorts the list with 'sort' and uses 'bisect_left' from the bisect module to perform binary search. It finds the position where x would fit and checks if x is actually present.
Time Complexity: O(n log n) for sorting, O(log n) for each search.
Space Complexity: O(1) when sorting in-place.
Approach 3: Sorting
The problem requires us to find the minimum and maximum values in the array nums each time, delete them, and then calculate the average of the two deleted numbers. Therefore, we can first sort the array nums, then take the first and last elements of the array each time, calculate their sum, use a hash table or array cnt to record the number of times each sum appears, and finally count the number of different sums.
The time complexity is O(n times log n), and the space complexity is O(n). Here, n is the length of the array nums.
function distinctAverages(nums: number[]): number {
nums.sort((a, b) => a - b);
const s: Set<number> = new Set();
const n = nums.length;
for (let i = 0; i < n >> 1; ++i) {
s.add(nums[i] + nums[n - i - 1]);
}
return s.size;
}func distinctAverages(nums []int) (ans int) {
sort.Ints(nums)
n := len(nums)
s := map[int]struct{}{}
for i := 0; i < n>>1; i++ {
s[nums[i]+nums[n-i-1]] = struct{}{}
}
return len(s)
}impl Solution {
pub fn distinct_averages(nums: Vec<i32>) -> i32 {
let mut nums = nums;
nums.sort();
let n = nums.len();
let mut cnt = vec![0; 201];
let mut ans = 0;
for i in 0..n >> 1 {
let x = (nums[i] + nums[n - i - 1]) as usize;
cnt[x] += 1;
if cnt[x] == 1 {
ans += 1;
}
}
ans
}
}Approach 4: Default Approach
function distinctAverages(nums: number[]): number {
nums.sort((a, b) => a - b);
const cnt: number[] = Array(201).fill(0);
let ans = 0;
const n = nums.length;
for (let i = 0; i < n >> 1; ++i) {
if (++cnt[nums[i] + nums[n - i - 1]] === 1) {
++ans;
}
}
return ans;
}func distinctAverages(nums []int) (ans int) {
sort.Ints(nums)
n := len(nums)
cnt := [201]int{}
for i := 0; i < n>>1; i++ {
x := nums[i] + nums[n-i-1]
cnt[x]++
if cnt[x] == 1 {
ans++
}
}
return
}use std::collections::HashMap;
impl Solution {
pub fn distinct_averages(nums: Vec<i32>) -> i32 {
let mut h = HashMap::new();
let mut nums = nums;
let mut ans = 0;
let n = nums.len();
nums.sort();
for i in 0..n >> 1 {
let x = nums[i] + nums[n - i - 1];
*h.entry(x).or_insert(0) += 1;
if *h.get(&x).unwrap() == 1 {
ans += 1;
}
}
ans
}
}Complexity comparison
| Approach | Complexity |
|---|---|
| Approach 1: Using Hash Maps | Time Complexity: O(1) average for insert and search, O(n) in the worst case. |
| Approach 2: Using Sorting and Binary Search | Time Complexity: O(n log n) for sorting, O(log n) for each search. |
| Sorting | – |
| Default Approach | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Hash Set with Pair Tracking | O(n log n) | O(n) | General solution when you need to track distinct averages efficiently |
| Sorting + Two Pointers | O(n log n) | O(n) | Preferred interview approach when pairing smallest and largest elements |
Frequently asked questions
Is Number of Distinct Averages easy or hard?
Number of Distinct Averages is classified as an Easy problem. The challenge mainly tests understanding of sorting and the two-pointer technique, along with using a set to track unique values.
How to solve Number of Distinct Averages in O(n)?
Achieving strict O(n) time is difficult because identifying smallest and largest elements repeatedly usually requires sorting or priority structures. Most implementations sort the array once and then use two pointers. The resulting complexity is O(n log n), which is considered optimal for this problem.
What is the best approach for Number of Distinct Averages?
The most practical approach is sorting the array and using two pointers from both ends. After sorting, pair the smallest and largest numbers, compute their average, and store it in a hash set to keep only unique values. The sorting step takes O(n log n) time and the pairing step takes O(n), giving an overall complexity of O(n log n) with O(n) extra space.
What data structure is used in Number of Distinct Averages?
A hash set (or hash map variant) is used to store averages and ensure uniqueness. The array is typically sorted first, and then two pointers select the smallest and largest elements at each step. The hash set allows O(1) average-time insertion and membership checks.
What is the time complexity of Number of Distinct Averages?
The optimal solution runs in O(n log n) time because the array must be sorted first. After sorting, pairing elements with two pointers takes O(n). Space complexity is O(n) due to the hash set used to track distinct averages.
Number of Distinct Averages Python or Java solution approach?
Both Python and Java implementations follow the same pattern: sort the array, use two pointers to pair elements, compute the average, and insert it into a set. Python typically uses a built-in set, while Java uses HashSet. The algorithmic complexity remains O(n log n) time and O(n) space.
Is Number of Distinct Averages asked at Google, Amazon, or Meta?
Problems involving pairing extremes, computing averages, and tracking unique results appear frequently in interviews at companies like Amazon, Google, and Meta. While this exact problem may not always appear, the underlying patterns—sorting, two pointers, and hash sets—are common interview topics.
