1685. Sum of Absolute Differences in a Sorted Array
Problem Description
You are given an integer array nums
that is sorted in non-decreasing order.
Your task is to build and return a new integer array result
with the same length as nums
. Each element result[i]
should be equal to the sum of absolute differences between nums[i]
and all other elements in the array.
More specifically, for each index i
, you need to calculate:
result[i] = |nums[i] - nums[0]| + |nums[i] - nums[1]| + ... + |nums[i] - nums[n-1]|
(excluding|nums[i] - nums[i]|
)
Since the array is sorted, we can optimize the calculation. For any element nums[i]
:
- All elements to the left (
nums[0]
tonums[i-1]
) are smaller than or equal tonums[i]
- All elements to the right (
nums[i+1]
tonums[n-1]
) are greater than or equal tonums[i]
This means:
- For elements on the left:
|nums[i] - nums[j]| = nums[i] - nums[j]
- For elements on the right:
|nums[i] - nums[j]| = nums[j] - nums[i]
The solution uses prefix sums to efficiently calculate these differences. It maintains:
s
: the total sum of all elementst
: the running sum of elements processed so far- For each
nums[i]
, the formulanums[i] * i - t + s - t - nums[i] * (len(nums) - i)
calculates the sum of absolute differences
This formula works because:
nums[i] * i - t
gives the sum of differences with elements on the lefts - t - nums[i] * (len(nums) - i)
gives the sum of differences with elements on the right (including the current element, which gets subtracted out)
Intuition
The key insight comes from recognizing that the array is sorted in non-decreasing order. This property allows us to avoid calculating absolute values conditionally.
For any element nums[i]
in a sorted array:
- All elements before it (indices
0
toi-1
) are smaller or equal, so|nums[i] - nums[j]| = nums[i] - nums[j]
- All elements after it (indices
i+1
ton-1
) are greater or equal, so|nums[i] - nums[j]| = nums[j] - nums[i]
Let's think about how to calculate the sum of absolute differences for nums[i]
:
Left side contribution:
- We need
(nums[i] - nums[0]) + (nums[i] - nums[1]) + ... + (nums[i] - nums[i-1])
- This simplifies to
nums[i] * i - (nums[0] + nums[1] + ... + nums[i-1])
- Which is
nums[i] * i - t
, wheret
is the sum of all elements before indexi
Right side contribution:
- We need
(nums[i+1] - nums[i]) + (nums[i+2] - nums[i]) + ... + (nums[n-1] - nums[i])
- This simplifies to
(nums[i+1] + nums[i+2] + ... + nums[n-1]) - nums[i] * (n - i - 1)
- The sum of elements after
i
iss - t - nums[i]
, wheres
is the total sum - So the contribution becomes
(s - t - nums[i]) - nums[i] * (n - i - 1)
- Which simplifies to
s - t - nums[i] * (n - i)
Combining both contributions:
result[i] = nums[i] * i - t + s - t - nums[i] * (n - i)
By maintaining a running sum t
as we iterate through the array, we can calculate each result[i]
in constant time, giving us an overall linear time complexity.
Learn more about Math and Prefix Sum patterns.
Solution Approach
We use a summation and enumeration approach to solve this problem efficiently in O(n) time.
Algorithm Steps:
-
Initialize variables:
- Calculate
s = sum(nums)
- the total sum of all elements in the array - Initialize
t = 0
- this will track the cumulative sum of elements we've processed - Create an empty list
ans
to store our results
- Calculate
-
Iterate through each element: For each element
nums[i]
at indexi
:-
Apply the formula:
v = nums[i] * i - t + s - t - nums[i] * (len(nums) - i)
This formula combines:
nums[i] * i - t
: Sum of differences with elements on the lefts - t - nums[i] * (len(nums) - i)
: Sum of differences with elements on the right
-
Store the result: Append
v
to our answer list -
Update the running sum: Add the current element to
t
witht += nums[i]
-
-
Return the result: After processing all elements, return the
ans
list
Implementation Details:
class Solution:
def getSumAbsoluteDifferences(self, nums: List[int]) -> List[int]:
ans = []
s, t = sum(nums), 0
for i, x in enumerate(nums):
v = x * i - t + s - t - x * (len(nums) - i)
ans.append(v)
t += x
return ans
The solution cleverly avoids nested loops by:
- Pre-computing the total sum
s
once at the beginning - Maintaining a running sum
t
to know the sum of elements before the current position - Using arithmetic to calculate the sum of elements after the current position as
s - t - nums[i]
Time Complexity: O(n) - We iterate through the array once after calculating the initial sum Space Complexity: O(1) - We only use a constant amount of extra space (excluding the output 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 the solution with a small example: nums = [2, 3, 5]
Step 1: Initialize variables
- Calculate total sum:
s = 2 + 3 + 5 = 10
- Initialize running sum:
t = 0
- Create empty result list:
ans = []
Step 2: Process each element
For i = 0, nums[0] = 2:
- Apply formula:
v = 2 * 0 - 0 + 10 - 0 - 2 * (3 - 0)
- Left contribution:
2 * 0 - 0 = 0
(no elements to the left) - Right contribution:
10 - 0 - 2 * 3 = 10 - 6 = 4
- Total:
v = 0 + 4 = 4
- Left contribution:
- Verify:
|2-3| + |2-5| = 1 + 3 = 4
✓ - Update:
ans = [4]
,t = 0 + 2 = 2
For i = 1, nums[1] = 3:
- Apply formula:
v = 3 * 1 - 2 + 10 - 2 - 3 * (3 - 1)
- Left contribution:
3 * 1 - 2 = 1
(difference with 2) - Right contribution:
10 - 2 - 3 * 2 = 8 - 6 = 2
(difference with 5) - Total:
v = 1 + 2 = 3
- Left contribution:
- Verify:
|3-2| + |3-5| = 1 + 2 = 3
✓ - Update:
ans = [4, 3]
,t = 2 + 3 = 5
For i = 2, nums[2] = 5:
- Apply formula:
v = 5 * 2 - 5 + 10 - 5 - 5 * (3 - 2)
- Left contribution:
5 * 2 - 5 = 5
(differences with 2 and 3) - Right contribution:
10 - 5 - 5 * 1 = 0
(no elements to the right) - Total:
v = 5 + 0 = 5
- Left contribution:
- Verify:
|5-2| + |5-3| = 3 + 2 = 5
✓ - Update:
ans = [4, 3, 5]
,t = 5 + 5 = 10
Step 3: Return result
- Final answer:
[4, 3, 5]
The formula efficiently calculates the sum by leveraging the sorted property, avoiding the need to compute absolute values individually.
Solution Implementation
1class Solution:
2 def getSumAbsoluteDifferences(self, nums: List[int]) -> List[int]:
3 # Initialize result array
4 result = []
5
6 # Calculate total sum of all elements
7 total_sum = sum(nums)
8
9 # Track cumulative sum of elements processed so far
10 cumulative_sum = 0
11
12 # Process each element in the array
13 for index, current_value in enumerate(nums):
14 # Calculate sum of absolute differences for current element
15 # Left part: current_value * index - cumulative_sum
16 # This gives sum of (current_value - nums[j]) for all j < index
17 # Right part: (total_sum - cumulative_sum - current_value) - current_value * (len(nums) - index - 1)
18 # This gives sum of (nums[j] - current_value) for all j > index
19 sum_absolute_diff = (current_value * index - cumulative_sum +
20 total_sum - cumulative_sum - current_value * (len(nums) - index))
21
22 # Add calculated sum to result
23 result.append(sum_absolute_diff)
24
25 # Update cumulative sum for next iteration
26 cumulative_sum += current_value
27
28 return result
29
1class Solution {
2 public int[] getSumAbsoluteDifferences(int[] nums) {
3 // Calculate the total sum of all elements in the array
4 int totalSum = 0;
5 for (int num : nums) {
6 totalSum += num;
7 }
8
9 int n = nums.length;
10 int[] result = new int[n];
11
12 // Track the cumulative sum of elements before current index
13 int prefixSum = 0;
14
15 // For each element, calculate sum of absolute differences
16 for (int i = 0; i < n; i++) {
17 // Calculate sum of absolute differences for nums[i]
18 // Left part: nums[i] * i - prefixSum (elements before index i)
19 // Right part: (totalSum - prefixSum - nums[i]) - nums[i] * (n - i - 1)
20 // = totalSum - prefixSum - nums[i] * (n - i)
21 int leftDifference = nums[i] * i - prefixSum;
22 int rightDifference = totalSum - prefixSum - nums[i] * (n - i);
23
24 result[i] = leftDifference + rightDifference;
25
26 // Update prefix sum for next iteration
27 prefixSum += nums[i];
28 }
29
30 return result;
31 }
32}
33
1class Solution {
2public:
3 vector<int> getSumAbsoluteDifferences(vector<int>& nums) {
4 // Calculate the total sum of all elements
5 int totalSum = accumulate(nums.begin(), nums.end(), 0);
6
7 // Initialize prefix sum (sum of elements before current index)
8 int prefixSum = 0;
9
10 // Get the size of the array
11 int n = nums.size();
12
13 // Initialize result array to store sum of absolute differences
14 vector<int> result(n);
15
16 // Iterate through each element to calculate its sum of absolute differences
17 for (int i = 0; i < n; ++i) {
18 // For sorted array, sum of absolute differences at index i:
19 // = (nums[i] * count_of_left_elements - sum_of_left_elements) +
20 // (sum_of_right_elements - nums[i] * count_of_right_elements)
21
22 // Left side contribution: nums[i] appears i times minus the prefix sum
23 int leftContribution = nums[i] * i - prefixSum;
24
25 // Right side contribution: remaining sum minus nums[i] appearing (n-i) times
26 // Note: remaining sum = totalSum - prefixSum - nums[i]
27 int rightContribution = (totalSum - prefixSum - nums[i]) - nums[i] * (n - i - 1);
28
29 // Total sum of absolute differences for current element
30 result[i] = leftContribution + rightContribution;
31
32 // Update prefix sum for next iteration
33 prefixSum += nums[i];
34 }
35
36 return result;
37 }
38};
39
1/**
2 * Calculate the sum of absolute differences for each element in a sorted array
3 * For each element at index i, compute sum of |nums[i] - nums[j]| for all j
4 * @param nums - A non-decreasing sorted array of integers
5 * @returns Array where result[i] is the sum of absolute differences for nums[i]
6 */
7function getSumAbsoluteDifferences(nums: number[]): number[] {
8 // Calculate the total sum of all elements in the array
9 const totalSum: number = nums.reduce((accumulator: number, current: number) => accumulator + current, 0);
10
11 // Initialize prefix sum to track sum of elements before current index
12 let prefixSum: number = 0;
13
14 // Get the length of the input array
15 const arrayLength: number = nums.length;
16
17 // Initialize result array to store the answer for each position
18 const result: number[] = new Array(arrayLength);
19
20 // Iterate through each element to calculate its sum of absolute differences
21 for (let currentIndex: number = 0; currentIndex < arrayLength; ++currentIndex) {
22 // Formula breakdown:
23 // - Left part: nums[i] * i - prefixSum (sum of differences with elements on the left)
24 // - Right part: (totalSum - prefixSum - nums[i]) - nums[i] * (n - i - 1) (sum of differences with elements on the right)
25 // Simplified: nums[i] * i - prefixSum + totalSum - prefixSum - nums[i] * (arrayLength - currentIndex)
26 const sumOfAbsoluteDifferences: number =
27 nums[currentIndex] * currentIndex - prefixSum +
28 totalSum - prefixSum - nums[currentIndex] * (arrayLength - currentIndex);
29
30 // Store the calculated result for current position
31 result[currentIndex] = sumOfAbsoluteDifferences;
32
33 // Update prefix sum for next iteration
34 prefixSum += nums[currentIndex];
35 }
36
37 return result;
38}
39
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the array nums
. The algorithm iterates through the array once with a single for loop, performing constant-time operations (arithmetic operations and list append) at each iteration. The initial sum(nums)
operation also takes O(n)
time, resulting in an overall time complexity of O(n) + O(n) = O(n)
.
The space complexity is O(1)
if we exclude the output array ans
. The algorithm only uses a constant amount of extra space for variables s
, t
, i
, x
, and v
, regardless of the input size. If we include the output array ans
which stores n
elements, the space complexity would be O(n)
, but typically when analyzing space complexity, the space required for the output is not counted.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Integer Overflow in Large Arrays
When dealing with large arrays or large integer values, the intermediate calculations (especially total_sum
and the formula components) might exceed the integer limit in some programming languages.
Example scenario:
- Array with 10^5 elements, each with value close to 10^9
- The total sum could reach 10^14, causing overflow in languages with 32-bit integers
Solution:
- In Python, this isn't an issue due to arbitrary precision integers
- In other languages (Java, C++), use long/long long data types
- Consider modular arithmetic if the problem requires it
2. Off-by-One Error in Formula
A common mistake is incorrectly calculating the number of elements on the right side, using (len(nums) - i)
instead of (len(nums) - i - 1)
.
Incorrect formula:
# Wrong: includes the current element in right side count
sum_diff = current_value * index - cumulative_sum +
(total_sum - cumulative_sum) - current_value * (len(nums) - index)
Correct approach:
# Right: properly accounts for elements only after current position
sum_diff = current_value * index - cumulative_sum +
(total_sum - cumulative_sum - current_value) - current_value * (len(nums) - index - 1)
3. Forgetting to Update Cumulative Sum
Failing to update cumulative_sum
after processing each element will cause incorrect calculations for subsequent elements.
Wrong implementation:
for index, current_value in enumerate(nums):
sum_diff = current_value * index - cumulative_sum +
total_sum - cumulative_sum - current_value * (len(nums) - index)
result.append(sum_diff)
# Missing: cumulative_sum += current_value
Fix: Always update cumulative_sum += current_value
at the end of each iteration.
4. Misunderstanding the Sorted Property
Attempting to use this formula on an unsorted array will produce incorrect results. The formula relies on the fact that all elements to the left are ≤ current element and all elements to the right are ≥ current element.
Solution:
- Verify the array is sorted before applying this algorithm
- If unsorted, either sort it first or use a different approach (brute force O(n²))
5. Edge Cases with Empty or Single-Element Arrays
Not handling edge cases properly can cause runtime errors or incorrect outputs.
Proper handling:
def getSumAbsoluteDifferences(self, nums: List[int]) -> List[int]:
if not nums: # Empty array
return []
if len(nums) == 1: # Single element
return [0]
# Continue with main algorithm...
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
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
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
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!