2574. Left and Right Sum Differences
Problem Description
You are given a 0-indexed integer array nums
of size n
. Your task is to create a new array where each element represents the absolute difference between the sum of elements to its left and the sum of elements to its right.
For each index i
in the array:
- The left sum is the sum of all elements that appear before index
i
(elements at indices0
toi-1
). If no elements exist to the left, the left sum is0
. - The right sum is the sum of all elements that appear after index
i
(elements at indicesi+1
ton-1
). If no elements exist to the right, the right sum is0
.
Your goal is to return an array answer
where answer[i] = |leftSum[i] - rightSum[i]|
for each index i
.
For example, if nums = [10, 4, 8, 3]
:
- At index 0: left sum =
0
(no elements to the left), right sum =4 + 8 + 3 = 15
, difference =|0 - 15| = 15
- At index 1: left sum =
10
, right sum =8 + 3 = 11
, difference =|10 - 11| = 1
- At index 2: left sum =
10 + 4 = 14
, right sum =3
, difference =|14 - 3| = 11
- At index 3: left sum =
10 + 4 + 8 = 22
, right sum =0
(no elements to the right), difference =|22 - 0| = 22
The result would be [15, 1, 11, 22]
.
Intuition
The key insight is that we don't need to calculate the left and right sums from scratch for each index. Instead, we can maintain running sums that we update as we traverse the array.
Initially, we know that:
- For index 0, the left sum is
0
and the right sum is the total sum minus the first element - As we move to the next index, the element we just passed becomes part of the left sum, and is no longer part of the right sum
This suggests a sliding window approach where we maintain two variables:
left
: starts at0
and accumulates elements as we pass themright
: starts with the total sum of all elements and decreases as we process each element
For each element at index i
:
- First, we remove the current element from
right
(since the right sum doesn't include the element at indexi
) - Now
left
andright
represent the exact sums we need for this index - We calculate
|left - right|
and add it to our answer - Finally, we add the current element to
left
(preparing for the next iteration)
This way, we only need a single pass through the array with constant time operations at each step, avoiding the need to recalculate sums repeatedly. The pattern of "subtract from right, calculate difference, add to left" elegantly handles the transition from one index to the next.
Learn more about Prefix Sum patterns.
Solution Approach
We implement the solution using a prefix sum technique with two running counters:
-
Initialize variables:
left = 0
: Tracks the sum of elements to the left of the current indexright = sum(nums)
: Initially holds the total sum of all elementsans = []
: Stores the result array
-
Single pass iteration: For each element
x
innums
:a. Update right sum:
right -= x
- This removes the current element from the right sum since the right sum for index
i
should not includenums[i]
b. Calculate and store the difference:
ans.append(abs(left - right))
- At this point,
left
contains the sum of all elements before indexi
- And
right
contains the sum of all elements after indexi
- We compute the absolute difference and add it to our answer
c. Update left sum:
left += x
- Add the current element to the left sum, preparing for the next iteration
- This removes the current element from the right sum since the right sum for index
-
Return the result: After processing all elements, return
ans
Example walkthrough with nums = [10, 4, 8, 3]
:
- Initial:
left = 0
,right = 25
,ans = []
- Index 0 (
x = 10
):right = 25 - 10 = 15
, append|0 - 15| = 15
,left = 0 + 10 = 10
- Index 1 (
x = 4
):right = 15 - 4 = 11
, append|10 - 11| = 1
,left = 10 + 4 = 14
- Index 2 (
x = 8
):right = 11 - 8 = 3
, append|14 - 3| = 11
,left = 14 + 8 = 22
- Index 3 (
x = 3
):right = 3 - 3 = 0
, append|22 - 0| = 22
,left = 22 + 3 = 25
- Result:
[15, 1, 11, 22]
The time complexity is O(n)
as we traverse the array once, and the space complexity is O(1)
if we don't count 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 nums = [2, 5, 1]
:
Initial Setup:
- Calculate total sum:
2 + 5 + 1 = 8
- Initialize:
left = 0
,right = 8
,ans = []
Processing Index 0 (value = 2):
- Update right sum:
right = 8 - 2 = 6
(remove current element from right) - Calculate difference:
|left - right| = |0 - 6| = 6
- Add to answer:
ans = [6]
- Update left sum:
left = 0 + 2 = 2
(add current element to left)
Processing Index 1 (value = 5):
- Update right sum:
right = 6 - 5 = 1
(remove current element from right) - Calculate difference:
|left - right| = |2 - 1| = 1
- Add to answer:
ans = [6, 1]
- Update left sum:
left = 2 + 5 = 7
(add current element to left)
Processing Index 2 (value = 1):
- Update right sum:
right = 1 - 1 = 0
(remove current element from right) - Calculate difference:
|left - right| = |7 - 0| = 7
- Add to answer:
ans = [6, 1, 7]
- Update left sum:
left = 7 + 1 = 8
(add current element to left)
Final Result: [6, 1, 7]
The key pattern to observe is how we maintain the invariant that at each step, after subtracting the current element from right
, we have exactly the sums we need to calculate the difference for that index. This eliminates redundant calculations and gives us an efficient O(n) solution.
Solution Implementation
1class Solution:
2 def leftRigthDifference(self, nums: List[int]) -> List[int]:
3 """
4 Calculate the absolute difference between left sum and right sum for each element.
5 For each index i, left sum is the sum of elements before i,
6 and right sum is the sum of elements after i.
7 """
8 # Initialize left sum as 0 (no elements to the left initially)
9 left_sum = 0
10 # Initialize right sum as the total sum of all elements
11 right_sum = sum(nums)
12
13 # List to store the absolute differences
14 result = []
15
16 # Iterate through each element in the array
17 for num in nums:
18 # Exclude current element from right sum (elements after current)
19 right_sum -= num
20
21 # Calculate and store the absolute difference between left and right sums
22 result.append(abs(left_sum - right_sum))
23
24 # Include current element in left sum for next iteration
25 left_sum += num
26
27 return result
28
1class Solution {
2 public int[] leftRigthDifference(int[] nums) {
3 // Initialize left sum as 0 and right sum as total sum of array
4 int leftSum = 0;
5 int rightSum = Arrays.stream(nums).sum();
6
7 // Get array length
8 int n = nums.length;
9
10 // Initialize result array
11 int[] result = new int[n];
12
13 // Iterate through each element
14 for (int i = 0; i < n; i++) {
15 // Exclude current element from right sum
16 rightSum -= nums[i];
17
18 // Calculate absolute difference between left and right sums
19 result[i] = Math.abs(leftSum - rightSum);
20
21 // Include current element in left sum for next iteration
22 leftSum += nums[i];
23 }
24
25 return result;
26 }
27}
28
1class Solution {
2public:
3 vector<int> leftRigthDifference(vector<int>& nums) {
4 // Initialize left sum as 0 and right sum as total sum of all elements
5 int leftSum = 0;
6 int rightSum = accumulate(nums.begin(), nums.end(), 0);
7
8 // Result vector to store the absolute differences
9 vector<int> result;
10
11 // Iterate through each element in the array
12 for (int& num : nums) {
13 // Exclude current element from right sum
14 rightSum -= num;
15
16 // Calculate absolute difference between left and right sums
17 result.push_back(abs(leftSum - rightSum));
18
19 // Include current element in left sum for next iteration
20 leftSum += num;
21 }
22
23 return result;
24 }
25};
26
1/**
2 * Calculates the absolute difference between left sum and right sum for each element
3 * @param nums - Array of numbers to process
4 * @returns Array where each element is the absolute difference between left and right sums
5 */
6function leftRigthDifference(nums: number[]): number[] {
7 // Initialize left sum as 0
8 let leftSum: number = 0;
9
10 // Initialize right sum as the total sum of all elements
11 let rightSum: number = nums.reduce((accumulator: number, current: number) => accumulator + current, 0);
12
13 // Array to store the results
14 const result: number[] = [];
15
16 // Iterate through each element in the array
17 for (const currentNum of nums) {
18 // Exclude current element from right sum
19 rightSum -= currentNum;
20
21 // Calculate absolute difference between left and right sums
22 result.push(Math.abs(leftSum - rightSum));
23
24 // Include current element in left sum for next iteration
25 leftSum += currentNum;
26 }
27
28 return result;
29}
30
Time and Space Complexity
Time Complexity: O(n)
- The initial
sum(nums)
operation takesO(n)
time to traverse through all elements - The for loop iterates through each element in
nums
exactly once, performing constant time operations (O(1)
) in each iteration: subtraction, absolute value calculation, append operation, and addition - Total time complexity:
O(n) + O(n) = O(n)
Space Complexity: O(n)
- The algorithm uses
O(1)
extra space for variablesleft
andright
- The
ans
list stores exactlyn
elements (one for each element innums
), requiringO(n)
space - Since the output array is typically required for the problem and counts toward space complexity, the total space complexity is
O(n)
- If we don't count the output array (as some analyses do), the auxiliary space complexity would be
O(1)
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Order of Operations
A common mistake is updating the left_sum
before calculating the difference, or forgetting to update right_sum
before the calculation. This leads to incorrect results because the sums would include or exclude the wrong elements.
Incorrect Implementation:
def leftRightDifference(self, nums: List[int]) -> List[int]:
left_sum = 0
right_sum = sum(nums)
result = []
for num in nums:
left_sum += num # ❌ Updated too early!
right_sum -= num
result.append(abs(left_sum - right_sum))
return result
Why it's wrong: For index i
, left_sum
should contain the sum of elements before index i
, not including nums[i]
. By adding num
to left_sum
before calculating the difference, we're including the current element in the left sum, which violates the problem requirements.
Correct Order:
- First, subtract current element from
right_sum
- Then, calculate the difference
- Finally, add current element to
left_sum
2. Typo in Method Name
The provided code has a typo: leftRigthDifference
instead of leftRightDifference
. This will cause the solution to fail on submission platforms that expect exact method names.
Fix:
def leftRightDifference(self, nums: List[int]) -> List[int]: # Note the spelling correction
3. Not Handling Edge Cases Mentally
While the code handles single-element arrays correctly, developers might overthink and add unnecessary special case handling:
Unnecessary complexity:
def leftRightDifference(self, nums: List[int]) -> List[int]:
if len(nums) == 1: # ❌ Unnecessary special case
return [0]
# rest of the code...
The algorithm naturally handles this case: for a single element, left_sum = 0
and right_sum = 0
after subtraction, giving |0 - 0| = 0
.
4. Using Two Passes When One Suffices
Some might calculate prefix and suffix sums in separate passes:
Inefficient approach:
def leftRightDifference(self, nums: List[int]) -> List[int]:
n = len(nums)
left_sums = [0] * n
right_sums = [0] * n
# First pass for left sums
for i in range(1, n):
left_sums[i] = left_sums[i-1] + nums[i-1]
# Second pass for right sums
for i in range(n-2, -1, -1):
right_sums[i] = right_sums[i+1] + nums[i+1]
# Third pass for differences
return [abs(left_sums[i] - right_sums[i]) for i in range(n)]
While correct, this uses O(n) extra space and multiple passes. The single-pass solution with running counters is more elegant and space-efficient.
Which type of traversal does breadth first search do?
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
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
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 assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!