3194. Minimum Average of Smallest and Largest Elements
Problem Description
You are given an array nums
containing n
integers where n
is even. You need to perform a series of operations to calculate averages and find the minimum among them.
The process works as follows:
- Start with an empty array called
averages
- Repeat the following steps
n/2
times:- Find and remove the smallest element (
minElement
) fromnums
- Find and remove the largest element (
maxElement
) fromnums
- Calculate the average of these two elements:
(minElement + maxElement) / 2
- Add this average to the
averages
array
- Find and remove the smallest element (
After completing all iterations, return the minimum value from the averages
array.
For example, if nums = [7, 8, 3, 4, 15, 13, 4, 1]
:
- First iteration: Remove 1 (min) and 15 (max), add
(1+15)/2 = 8
to averages - Second iteration: Remove 3 (min) and 13 (max), add
(3+13)/2 = 8
to averages - Third iteration: Remove 4 (min) and 8 (max), add
(4+8)/2 = 6
to averages - Fourth iteration: Remove 4 (min) and 7 (max), add
(4+7)/2 = 5.5
to averages - The
averages
array is[8, 8, 6, 5.5]
, so return5.5
The solution sorts the array first, then pairs up elements from opposite ends (smallest with largest, second smallest with second largest, etc.) to efficiently calculate all the averages and find the minimum.
Intuition
The key insight is recognizing that we're repeatedly pairing the smallest and largest remaining elements. Instead of actually removing elements from the array in each iteration, we can predict which elements will be paired together.
Think about what happens when we sort the array first. In each iteration:
- The smallest element will always come from the left side of our sorted array
- The largest element will always come from the right side of our sorted array
After sorting, the pairing pattern becomes clear:
- 1st iteration: first element pairs with last element
- 2nd iteration: second element pairs with second-to-last element
- 3rd iteration: third element pairs with third-to-last element
- And so on...
This means we can determine all the pairs upfront by sorting the array once and then pairing elements at index i
with elements at index n-1-i
.
For example, with sorted array [1, 3, 4, 4, 7, 8, 13, 15]
:
- Pair 1:
nums[0]
withnums[7]
โ (1, 15) - Pair 2:
nums[1]
withnums[6]
โ (3, 13) - Pair 3:
nums[2]
withnums[5]
โ (4, 8) - Pair 4:
nums[3]
withnums[4]
โ (4, 7)
Since we need to find the minimum average, and all averages are calculated by (minElement + maxElement) / 2
, we can first find the minimum sum among all pairs, then divide by 2 at the end. This is more efficient than calculating each average separately.
The solution elegantly captures this pattern: sort once, iterate through half the array to form pairs from opposite ends, track the minimum sum, and finally divide by 2.
Learn more about Two Pointers and Sorting patterns.
Solution Approach
The implementation follows a straightforward sorting-based approach:
-
Sort the array: First, we sort
nums
in ascending order usingnums.sort()
. This allows us to easily identify which elements will be paired together - the smallest remaining element will always be at the left end, and the largest at the right end. -
Calculate the length: Store
n = len(nums)
for convenience. -
Find minimum sum among pairs: We iterate through the first half of the sorted array (
range(n // 2)
). For each indexi
:- Pair the element at index
i
(from the left) with the element at index-i - 1
(from the right) - Calculate the sum:
nums[i] + nums[-i - 1]
- The negative indexing
-i - 1
gives us:- When
i = 0
:nums[-1]
(last element) - When
i = 1
:nums[-2]
(second-to-last element) - And so on...
- When
- Pair the element at index
-
Return the minimum average: Use Python's
min()
function with a generator expression to find the minimum sum among all pairs, then divide by 2 to get the average.
The entire solution is condensed into a single line after sorting:
return min(nums[i] + nums[-i - 1] for i in range(n // 2)) / 2
This generator expression efficiently computes all pair sums without storing them in memory, finds the minimum, and returns half of that value as the final answer.
Time Complexity: O(n log n)
due to sorting, where n
is the length of the input array.
Space Complexity: O(1)
if we don't count the space used by sorting (in-place sort), otherwise O(n)
for the sorting algorithm's space requirements.
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 nums = [5, 2, 8, 3]
:
Step 1: Sort the array
- Original:
[5, 2, 8, 3]
- After sorting:
[2, 3, 5, 8]
Step 2: Identify pairs using the two-pointer approach
- Since
n = 4
, we needn/2 = 2
iterations - We'll pair elements from opposite ends:
- When
i = 0
: Pairnums[0]
withnums[-1]
โ2
with8
- When
i = 1
: Pairnums[1]
withnums[-2]
โ3
with5
- When
Step 3: Calculate sums for each pair
- Pair 1:
nums[0] + nums[-1] = 2 + 8 = 10
- Pair 2:
nums[1] + nums[-2] = 3 + 5 = 8
Step 4: Find minimum sum and calculate average
- All sums:
[10, 8]
- Minimum sum:
8
- Minimum average:
8 / 2 = 4
Verification with original problem approach:
- Start with
[5, 2, 8, 3]
- Iteration 1: Remove min(2) and max(8), average =
(2+8)/2 = 5
- Iteration 2: Remove min(3) and max(5), average =
(3+5)/2 = 4
- Averages array:
[5, 4]
- Minimum:
4
โ
The sorted approach correctly predicts that elements 2 and 8 will be paired first, then 3 and 5, giving us the same result with just one sort operation instead of repeatedly finding min/max values.
Solution Implementation
1class Solution:
2 def minimumAverage(self, nums: List[int]) -> float:
3 # Sort the array in ascending order
4 nums.sort()
5
6 # Get the length of the array
7 n = len(nums)
8
9 # Find the minimum sum of pairs (smallest + largest, 2nd smallest + 2nd largest, etc.)
10 # and divide by 2 to get the average
11 # We iterate through the first half of the array and pair each element
12 # with its corresponding element from the end
13 min_sum = min(nums[i] + nums[-i - 1] for i in range(n // 2))
14
15 # Return the minimum average
16 return min_sum / 2
17
1class Solution {
2 public double minimumAverage(int[] nums) {
3 // Sort the array in ascending order
4 Arrays.sort(nums);
5
6 // Get the length of the array
7 int n = nums.length;
8
9 // Initialize minimum sum to a large value (2^30)
10 int minSum = 1 << 30;
11
12 // Iterate through the first half of the array
13 // Pair elements from start and end to find minimum sum
14 for (int i = 0; i < n / 2; i++) {
15 // Calculate sum of current pair (smallest and largest remaining elements)
16 int currentSum = nums[i] + nums[n - i - 1];
17
18 // Update minimum sum if current sum is smaller
19 minSum = Math.min(minSum, currentSum);
20 }
21
22 // Return the average of the minimum sum pair
23 return minSum / 2.0;
24 }
25}
26
1class Solution {
2public:
3 double minimumAverage(vector<int>& nums) {
4 // Sort the array to easily pair smallest and largest elements
5 sort(nums.begin(), nums.end());
6
7 // Initialize minimum sum with a large value (2^30)
8 int minSum = 1 << 30;
9 int n = nums.size();
10
11 // Iterate through half of the array
12 // Pair element at index i with element at index (n-i-1)
13 // This pairs: first with last, second with second-last, etc.
14 for (int i = 0; i < n / 2; ++i) {
15 int currentSum = nums[i] + nums[n - i - 1];
16 minSum = min(minSum, currentSum);
17 }
18
19 // Return the average by dividing the minimum sum by 2
20 return minSum / 2.0;
21 }
22};
23
1/**
2 * Finds the minimum average of pairs formed by taking the smallest and largest elements
3 * @param nums - Array of numbers to process
4 * @returns The minimum average value among all possible pairs
5 */
6function minimumAverage(nums: number[]): number {
7 // Sort the array in ascending order
8 nums.sort((a: number, b: number) => a - b);
9
10 // Get the length of the array
11 const arrayLength: number = nums.length;
12
13 // Initialize the minimum sum to infinity
14 let minimumSum: number = Infinity;
15
16 // Iterate through the first half of the array
17 // Pair each element with its corresponding element from the end
18 for (let i: number = 0; i * 2 < arrayLength; ++i) {
19 // Calculate sum of current pair (smallest + largest remaining elements)
20 const currentPairSum: number = nums[i] + nums[arrayLength - 1 - i];
21
22 // Update minimum sum if current pair sum is smaller
23 minimumSum = Math.min(minimumSum, currentPairSum);
24 }
25
26 // Return the minimum average (sum divided by 2)
27 return minimumSum / 2;
28}
29
Time and Space Complexity
Time Complexity: O(n log n)
The dominant operation in this code is nums.sort()
, which uses Python's Timsort algorithm with a time complexity of O(n log n)
, where n
is the length of the array. After sorting, the code performs a generator expression that iterates through n // 2
elements, creating n // 2
sums, and then finds the minimum among them. This takes O(n)
time. Since O(n log n) + O(n) = O(n log n)
, the overall time complexity is O(n log n)
.
Space Complexity: O(log n)
Python's sort()
method sorts the list in-place and uses O(log n)
space for the recursion stack in the worst case (Timsort requires O(log n)
auxiliary space for its merge operations). The generator expression (nums[i] + nums[-i - 1] for i in range(n // 2))
doesn't create a list but generates values on-the-fly, using O(1)
additional space. The min()
function processes the generator without storing all values, also using O(1)
space. Therefore, the overall space complexity is O(log n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Integer Division Instead of Float Division
A common mistake is accidentally using integer division when calculating the average, which can lead to incorrect results when the sum is odd.
Incorrect approach:
# Using // instead of / will truncate the decimal part
return min(nums[i] + nums[-i - 1] for i in range(n // 2)) // 2 # Wrong!
Correct approach:
# Use / for true division to get float results
return min(nums[i] + nums[-i - 1] for i in range(n // 2)) / 2
2. Misunderstanding the Pairing Logic
Some might incorrectly pair consecutive elements or use wrong indices when pairing elements from opposite ends.
Incorrect approach:
# Wrong: Pairing consecutive elements
min_avg = min((nums[i] + nums[i+1]) / 2 for i in range(0, n, 2))
# Wrong: Incorrect indexing from the end
min_avg = min((nums[i] + nums[n-i]) / 2 for i in range(n // 2)) # Off by one error
Correct approach:
# Pair element at index i with element at index -i-1 (or n-i-1)
min_avg = min((nums[i] + nums[-i-1]) / 2 for i in range(n // 2))
3. Forgetting to Sort the Array
The algorithm relies on the array being sorted to correctly identify min/max pairs. Forgetting this step will produce incorrect results.
Incorrect approach:
def minimumAverage(self, nums: List[int]) -> float:
# Forgot to sort!
n = len(nums)
return min(nums[i] + nums[-i - 1] for i in range(n // 2)) / 2
Correct approach:
def minimumAverage(self, nums: List[int]) -> float:
nums.sort() # Essential step!
n = len(nums)
return min(nums[i] + nums[-i - 1] for i in range(n // 2)) / 2
4. Attempting to Modify Array During Iteration
Trying to actually remove elements from the array as described in the problem statement, rather than using the sorted pairing approach.
Incorrect and inefficient approach:
averages = []
while nums:
min_val = min(nums)
nums.remove(min_val) # O(n) operation
max_val = max(nums)
nums.remove(max_val) # O(n) operation
averages.append((min_val + max_val) / 2)
return min(averages)
This approach has O(nยฒ) time complexity due to repeated min/max finding and removal operations, compared to the O(n log n) sorting approach.
You are given an array of intervals where intervals[i] = [start_i, end_i]
represent the start and end of the ith
interval. You need to merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.
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
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
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Donโt Miss This!