Facebook Pixel

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:

  1. Start with an empty array called averages
  2. Repeat the following steps n/2 times:
    • Find and remove the smallest element (minElement) from nums
    • Find and remove the largest element (maxElement) from nums
    • Calculate the average of these two elements: (minElement + maxElement) / 2
    • Add this average to the averages array

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 return 5.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.

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

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] with nums[7] โ†’ (1, 15)
  • Pair 2: nums[1] with nums[6] โ†’ (3, 13)
  • Pair 3: nums[2] with nums[5] โ†’ (4, 8)
  • Pair 4: nums[3] with nums[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:

  1. Sort the array: First, we sort nums in ascending order using nums.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.

  2. Calculate the length: Store n = len(nums) for convenience.

  3. Find minimum sum among pairs: We iterate through the first half of the sorted array (range(n // 2)). For each index i:

    • 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...
  4. 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 Evaluator

Example 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 need n/2 = 2 iterations
  • We'll pair elements from opposite ends:
    • When i = 0: Pair nums[0] with nums[-1] โ†’ 2 with 8
    • When i = 1: Pair nums[1] with nums[-2] โ†’ 3 with 5

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.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

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

Want a Structured Path to Master System Design Too? Donโ€™t Miss This!

Load More