2256. Minimum Average Difference
Problem Description
This problem deals with an array of integers where the task is to find the index that minimizes the average difference between the two segments of the array divided by that index. The array is split at every index from 0 to n - 1
, creating two non-overlapping segments. The left segment includes all elements from the beginning of the array to the current index, and the right segment includes all elements after the current index to the end of the array.
The average difference at an index i
is the absolute difference between the average of the numbers to the left of (and including) i
and the average of the numbers to the right of i
. The averages are calculated as the sum of the elements in the segment divided by the number of elements in the segment, with the result rounded down to the nearest integer. If the right segment is empty (which happens when i
is the last index), its average is considered to be 0.
The problem asks to determine the index that has the minimum average difference and to return the smallest index if there are multiple such indices.
Intuition
To solve this problem, one intuitive approach is to process each index and calculate the two averages (left and right segment averages) and their absolute difference. However, computing the sum of elements repeatedly for each index would result in a higher time complexity.
A more efficient method involves prefix sums, which can significantly optimize the repeated sum calculations. By maintaining a running total sum from the start of the array (pre
) and a running total sum from the end of the array (suf
), it becomes easier to compute the averages quickly at each index. As the index moves from left to right, elements are transferred from the right segment to the left segment. This is done by adding the current element to pre
and subtracting it from suf
.
The solution tracks the smallest average difference found (mi
) and its corresponding index (ans
). For each index i
, it calculates the average of the left segment, the average of the right segment (except when the right segment is empty), and their absolute difference (t
). If t
is smaller than the smallest difference seen so far, mi
is updated with t
and ans
with i
. After traversing all indices, the index corresponding to the minimal average difference is returned.
This approach efficiently narrows down the index with the minimum average difference without calculating the sum for each segment more than once, resulting in an overall time complexity of O(n), where n is the length of the array.
Learn more about Prefix Sum patterns.
Solution Approach
The implementation of the solution uses a simple loop through the array and exploits the concept of prefix sums to efficiently calculate the averages required for the problem statement. The algorithm doesn't require any complex data structures or patterns beyond arrays and basic arithmetic operations.
Here’s the step-by-step implementation of the solution:
-
Initialize two variables
pre
andsuf
. Setpre
to 0 because, initially, there are no elements in the left segment. Setsuf
to the sum of all elements innums
- this represents the sum of the right segment before any iteration. -
Set up variables
ans
for storing the index of the minimum average difference found, andmi
for storing the minimum average difference itself.mi
is initialized toinf
, which is a placeholder for infinity, to ensure that any actual difference calculated will be less than this initial value. -
Iterate over the elements in
nums
. For each indexi
and its corresponding valuex
innums
, do the following:- Add
x
topre
, asx
is now part of the left segment. - Subtract
x
fromsuf
, asx
is no longer part of the right segment. - Calculate the average of the left segment as
a = pre // (i + 1)
. - If the right segment is non-empty (determined by
n - i - 1 > 0
), calculate its average asb = suf // (n - i - 1)
. If the right segment is empty, setb
to 0. - Calculate the absolute difference between the two averages
t = abs(a - b)
.
- Add
-
If the absolute difference
t
is less than the current minimummi
, updatemi
witht
andans
with the current indexi
. -
After the loop completes, the variable
ans
holds the index of the minimum average difference. Returnans
as the result.
The algorithm solely uses integer division and basic arithmetic operations, which creates an efficient way of obtaining the minimum average difference without recalculating the sums for each segment for every index. The time complexity is O(n) because the algorithm requires a single pass through the array, and the space complexity is O(1) as it only uses a fixed number of extra variables.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's consider the array nums = [3, 1, 2, 4, 3]
to illustrate the solution approach.
-
Start by initializing
pre
to 0 andsuf
to the sum of all elements innums
, which is3 + 1 + 2 + 4 + 3 = 13
. Also, initializemi
to infinity, andans
to -1 (which will later hold the index of the minimum average difference). -
Now, iteratively process each element of the array:
-
For index
i = 0
:- Left Segment
[3]
and Right Segment[1, 2, 4, 3]
pre = 0 + 3 = 3
suf = 13 - 3 = 10
- Left average
a = 3 // 1 = 3
- Right average
b = 10 // 4 = 2
- Absolute difference
t = abs(3 - 2) = 1
- Since
t < mi
(1 < infinity), updatemi
to 1 andans
to 0.
- Left Segment
-
For index
i = 1
:- Left Segment
[3, 1]
and Right Segment[2, 4, 3]
pre = 3 + 1 = 4
suf = 10 - 1 = 9
- Left average
a = 4 // 2 = 2
- Right average
b = 9 // 3 = 3
- Absolute difference
t = abs(2 - 3) = 1
- Since
t = mi
(1 == 1), no update tomi
orans
as we pick the smallest index.
- Left Segment
-
For index
i = 2
:- Left Segment
[3, 1, 2]
and Right Segment[4, 3]
pre = 4 + 2 = 6
suf = 9 - 2 = 7
- Left average
a = 6 // 3 = 2
- Right average
b = 7 // 2 = 3
- Absolute difference
t = abs(2 - 3) = 1
- Since
t = mi
(1 == 1), no update asans
is already at the smallest index 0.
- Left Segment
-
For index
i = 3
:- Left Segment
[3, 1, 2, 4]
and Right Segment[3]
pre = 6 + 4 = 10
suf = 7 - 4 = 3
- Left average
a = 10 // 4 = 2
- Right average
b = 3 // 1 = 3
- Absolute difference
t = abs(2 - 3) = 1
- Because
t = mi
(1 == 1), there's no update needed.
- Left Segment
-
For index
i = 4
:- Left Segment
[3, 1, 2, 4, 3]
and no Right Segment pre = 10 + 3 = 13
suf = 3 - 3 = 0
- Left average
a = 13 // 5 = 2
- Right average
b = 0
(since there are no elements on the right) - Absolute difference
t = abs(2 - 0) = 2
- No update required as
t > mi
(2 > 1).
- Left Segment
-
-
After processing all indices, the smallest average difference
mi
is 1, and theans
associated with this difference is at index 0. -
The result returned is
ans = 0
, which is the index of the minimum average difference.
In this example, the process was performed in a single pass (O(n) time complexity), and we did not require extra space aside from a few variables (O(1) space complexity). This walkthrough demonstrates the efficiency and correctness of the proposed solution.
Solution Implementation
1class Solution:
2 def minimumAverageDifference(self, nums: List[int]) -> int:
3 # Initialize prefix sum, suffix sum, and the number of elements
4 prefix_sum, suffix_sum = 0, sum(nums)
5 num_elements = len(nums)
6
7 # Initialize variables to track the minimum average difference and its index
8 min_index, min_difference = 0, float('inf')
9
10 # Iterate through the list to calculate the differences
11 for index, value in enumerate(nums):
12 # Update the prefix and suffix sums
13 prefix_sum += value
14 suffix_sum -= value
15
16 # Calculate the average of the prefix and suffix
17 prefix_avg = prefix_sum // (index + 1)
18 # Calculate the average of suffix; handle the case when it becomes empty
19 suffix_avg = 0 if num_elements - index - 1 == 0 else suffix_sum // (num_elements - index - 1)
20
21 # Calculate the absolute difference of the averages
22 current_difference = abs(prefix_avg - suffix_avg)
23
24 # If the current difference is smaller than the recorded minimum, update the result
25 if current_difference < min_difference:
26 min_index = index
27 min_difference = current_difference
28
29 # Return the index of the element that gives the minimum average difference
30 return min_index
31
1class Solution {
2 public int minimumAverageDifference(int[] nums) {
3 // Get the length of the input array
4 int arrayLength = nums.length;
5 // Initialize prefix sum and suffix sum variables
6 long prefixSum = 0, suffixSum = 0;
7
8 // Calculate the total sum of the array elements (suffixSum)
9 for (int number : nums) {
10 suffixSum += number;
11 }
12
13 // Initialize the variable to store the index of the result
14 int resultIndex = 0;
15 // Initialize the minimum difference variable with the maximum value possible
16 long minimumDifference = Long.MAX_VALUE;
17
18 // Iterate through the array to calculate prefix and suffix sums dynamically
19 for (int i = 0; i < arrayLength; ++i) {
20 // Add the current number to the prefix sum
21 prefixSum += nums[i];
22 // Subtract the current number from the suffix sum
23 suffixSum -= nums[i];
24
25 // Calculate the average of the prefix part
26 long prefixAvg = prefixSum / (i + 1);
27 // Calculate the average of the suffix part, or set to 0 if there are no elements remaining
28 long suffixAvg = arrayLength - i - 1 == 0 ? 0 : suffixSum / (arrayLength - i - 1);
29 // Calculate the absolute difference between the two averages
30 long currentDifference = Math.abs(prefixAvg - suffixAvg);
31
32 // If the current difference is less than the minimum found so far, update the result and minimum
33 if (currentDifference < minimumDifference) {
34 resultIndex = i;
35 minimumDifference = currentDifference;
36 }
37 }
38 // Return the index where the absolute difference between the averages is minimum
39 return resultIndex;
40 }
41}
42
1#include <vector>
2#include <numeric> // for std::accumulate
3#include <cmath> // for std::abs
4
5class Solution {
6public:
7 int minimumAverageDifference(std::vector<int>& nums) {
8 int numElements = nums.size(); // Get the total number of elements in nums.
9 using ll = long long; // Use 'll' as an alias for 'long long' type for larger numbers.
10 ll prefixSum = 0; // Initialize prefix sum of first part of the array.
11 ll suffixSum = std::accumulate(nums.begin(), nums.end(), 0LL); // Calculate the sum of all elements in the array.
12
13 int minIndex = 0; // Store the index at which the minimum average difference occurs.
14 ll minDifference = suffixSum; // Initially set the minimum difference to the suffix sum.
15
16 for (int i = 0; i < numElements; ++i) {
17 prefixSum += nums[i]; // Add the current element to the prefix sum.
18 suffixSum -= nums[i]; // Remove the current element from the suffix sum.
19
20 ll prefixAvg = prefixSum / (i + 1); // Calculate average of the prefix part.
21 ll suffixAvg = (numElements - i - 1 == 0) ? 0 : // Calculate average of the suffix part,
22 suffixSum / (numElements - i - 1); // avoid division by zero by checking the size.
23
24 ll currentDifference = std::abs(prefixAvg - suffixAvg); // Calculate absolute difference between averages.
25
26 if (currentDifference < minDifference) { // Check if the current difference is less
27 minIndex = i; // than the minimum difference found so far.
28 minDifference = currentDifference; // If so, update minimum difference and index.
29 }
30 }
31 return minIndex; // Return the index of the minimum average difference.
32 }
33};
34
1function minimumAverageDifference(nums: number[]): number {
2 const lengthOfNums = nums.length; // Length of the input array
3
4 // Prefix sum which starts at zero and will store the sum of the elements before the current index
5 let prefixSum = 0;
6
7 // Suffix sum which starts as the sum of all elements and will store the sum of the elements after the current index
8 let suffixSum = nums.reduce((acc, current) => acc + current, 0);
9
10 // The index with the smallest average difference
11 let minDifferenceIndex = 0;
12
13 // The smallest average difference encountered so far initialized with a value that suffix sum contributes to before any iteration
14 let minimumDifference = suffixSum;
15
16 for (let index = 0; index < lengthOfNums; ++index) {
17 prefixSum += nums[index]; // Add current element to the prefix sum
18 suffixSum -= nums[index]; // Subtract current element from the suffix sum
19
20 // Calculate the average of the prefix by dividing prefixSum by the number of elements considered
21 const prefixAverage = Math.floor(prefixSum / (index + 1));
22
23 // Calculate the average of the suffix, checking for division by zero when index is at the last element
24 const suffixAverage = (lengthOfNums - index - 1) === 0 ? 0 : Math.floor(suffixSum / (lengthOfNums - index - 1));
25
26 // Calculate the absolute difference between the prefix and suffix averages
27 const difference = Math.abs(prefixAverage - suffixAverage);
28
29 if (difference < minimumDifference) {
30 // If the current difference is smaller, update minDifferenceIndex and minimumDifference
31 minDifferenceIndex = index;
32 minimumDifference = difference;
33 }
34 }
35
36 return minDifferenceIndex; // Return the index where the minimum average difference occurs
37}
38
Time and Space Complexity
The time complexity of the provided code is O(n)
, where n
is the length of the array nums
. The calculation of the sum of the array sum(nums)
is done in O(n)
. Inside the loop, only constant time operations are done, and since the loop runs n
times, the loop operations also amount to O(n)
. Thus, the entire function runs in linear time with respect to the size of the array.
The space complexity of the code is O(1)
. Independent of the length of the input array, a fixed number of variables are used (pre
, suf
, n
, ans
, mi
, a
, b
, and t
). These require a constant amount of space, and hence the space complexity does not scale with the input size.
Learn more about how to find time and space complexity quickly using problem constraints.
A person thinks of a number between 1 and 1000. You may ask any number questions to them, provided that the question can be answered with either "yes" or "no".
What is the minimum number of questions you needed to ask so that you are guaranteed to know the number that the person is thinking?
Recommended Readings
Prefix Sum The prefix sum is an incredibly powerful and straightforward technique Its primary goal is to allow for constant time range sum queries on an array What is Prefix Sum The prefix sum of an array at index i is the sum of all numbers from index 0 to i By
LeetCode 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 we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!