Facebook Pixel

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] to nums[i-1]) are smaller than or equal to nums[i]
  • All elements to the right (nums[i+1] to nums[n-1]) are greater than or equal to nums[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 elements
  • t: the running sum of elements processed so far
  • For each nums[i], the formula nums[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 left
  • s - t - nums[i] * (len(nums) - i) gives the sum of differences with elements on the right (including the current element, which gets subtracted out)
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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 to i-1) are smaller or equal, so |nums[i] - nums[j]| = nums[i] - nums[j]
  • All elements after it (indices i+1 to n-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, where t is the sum of all elements before index i

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 is s - t - nums[i], where s 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:

  1. 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
  2. Iterate through each element: For each element nums[i] at index i:

    • 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 left
      • s - 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 with t += nums[i]

  3. 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 Evaluator

Example 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
  • 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
  • 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
  • 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...
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

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

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More