Facebook Pixel

1749. Maximum Absolute Sum of Any Subarray

Problem Description

You are given an integer array nums. Your task is to find the maximum absolute sum among all possible subarrays (including empty subarrays).

The absolute sum of a subarray is calculated by taking the sum of all elements in that subarray and then applying the absolute value function to the result. For example, if a subarray has elements [a, b, c], its absolute sum would be |a + b + c|.

The absolute value function abs(x) works as follows:

  • If x is negative, then abs(x) = -x (makes it positive)
  • If x is non-negative, then abs(x) = x (stays the same)

A subarray is a contiguous sequence of elements from the array. It can be empty (in which case the sum would be 0), contain just one element, or contain multiple consecutive elements.

For example, if nums = [1, -3, 2, 3, -4]:

  • The subarray [2, 3] has sum 5, so its absolute sum is |5| = 5
  • The subarray [-3, 2, 3, -4] has sum -2, so its absolute sum is |-2| = 2
  • The subarray [2, 3, -4] has sum 1, so its absolute sum is |1| = 1

Your goal is to return the maximum possible absolute sum among all subarrays of the given array.

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

Intuition

To find the maximum absolute sum, we need to think about what values could give us the largest result after applying the absolute value function. The key insight is that the maximum absolute sum could come from either:

  1. A subarray with the largest positive sum
  2. A subarray with the most negative sum (which becomes positive after applying absolute value)

This means we need to track both extremes - the maximum sum and the minimum sum possible for subarrays ending at each position.

Think of it this way: if we're looking for max(|sum|), this is equivalent to finding max(maximum_sum, |minimum_sum|). Since the absolute value of the most negative number could be larger than the most positive number, we can't just look for the maximum sum alone.

For example, if we have an array like [1, -3, -4]:

  • The maximum sum subarray might be [1] with sum 1
  • But the minimum sum subarray is [-3, -4] with sum -7
  • After applying absolute value, |-7| = 7 is larger than 1

This leads us to use a dynamic programming approach where we maintain two running values:

  • f: tracks the maximum sum of subarrays ending at the current position
  • g: tracks the minimum sum of subarrays ending at the current position

At each position, we decide whether to extend the previous subarray or start fresh:

  • For maximum: f = max(f + current_element, current_element) which simplifies to max(f, 0) + current_element
  • For minimum: g = min(g + current_element, current_element) which simplifies to min(g, 0) + current_element

The answer is the maximum among all the maximum sums and the absolute values of all the minimum sums encountered during the traversal.

Learn more about Dynamic Programming patterns.

Solution Approach

The solution implements a dynamic programming approach using Kadane's algorithm variant that tracks both maximum and minimum subarray sums simultaneously.

Implementation Details:

We use two variables to maintain our dynamic programming states:

  • f: represents the maximum sum of subarrays ending at the current position
  • g: represents the minimum sum of subarrays ending at the current position
  • ans: keeps track of the maximum absolute sum found so far

Algorithm Steps:

  1. Initialize f = 0 and g = 0 as the maximum and minimum sums before processing any elements
  2. Initialize ans = 0 to store the result
  3. For each element x in the array:
    • Update maximum sum: f = max(f, 0) + x
      • This means: either extend the previous maximum subarray (f + x) or start a new subarray from current element (0 + x)
    • Update minimum sum: g = min(g, 0) + x
      • This means: either extend the previous minimum subarray (g + x) or start a new subarray from current element (0 + x)
    • Update answer: ans = max(ans, f, abs(g))
      • Compare current answer with the new maximum sum and the absolute value of the new minimum sum

State Transition Equations:

The core logic follows these recurrence relations:

f[i] = max(f[i-1], 0) + nums[i]
g[i] = min(g[i-1], 0) + nums[i]

Where:

  • f[i] represents the maximum sum ending at index i
  • g[i] represents the minimum sum ending at index i

Space Optimization:

Instead of using arrays to store all f[i] and g[i] values, we only need the previous state to compute the current state. This optimization reduces space complexity from O(n) to O(1).

Time and Space Complexity:

  • Time Complexity: O(n) - single pass through the array
  • Space Complexity: O(1) - only using constant extra space for variables

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with nums = [2, -5, 1, -4, 3, -2]

We'll track three variables:

  • f: maximum sum ending at current position
  • g: minimum sum ending at current position
  • ans: maximum absolute sum found so far

Initial state: f = 0, g = 0, ans = 0

Step 1: Process element 2

  • f = max(0, 0) + 2 = 2 (start new subarray [2])
  • g = min(0, 0) + 2 = 2 (start new subarray [2])
  • ans = max(0, 2, |2|) = 2

Step 2: Process element -5

  • f = max(2, 0) + (-5) = -3 (extend to [2, -5])
  • g = min(2, 0) + (-5) = -5 (start new subarray [-5])
  • ans = max(2, -3, |-5|) = 5

Step 3: Process element 1

  • f = max(-3, 0) + 1 = 1 (start new subarray [1])
  • g = min(-5, 0) + 1 = -4 (extend to [-5, 1])
  • ans = max(5, 1, |-4|) = 5

Step 4: Process element -4

  • f = max(1, 0) + (-4) = -3 (extend to [1, -4])
  • g = min(-4, 0) + (-4) = -8 (extend to [-5, 1, -4])
  • ans = max(5, -3, |-8|) = 8

Step 5: Process element 3

  • f = max(-3, 0) + 3 = 3 (start new subarray [3])
  • g = min(-8, 0) + 3 = -5 (extend to [-5, 1, -4, 3])
  • ans = max(8, 3, |-5|) = 8

Step 6: Process element -2

  • f = max(3, 0) + (-2) = 1 (extend to [3, -2])
  • g = min(-5, 0) + (-2) = -7 (extend to [-5, 1, -4, 3, -2])
  • ans = max(8, 1, |-7|) = 8

Final answer: 8 (from the subarray [-5, 1, -4] with sum -8, giving absolute sum 8)

Solution Implementation

1class Solution:
2    def maxAbsoluteSum(self, nums: List[int]) -> int:
3        # Track maximum sum subarray (Kadane's algorithm variant)
4        max_sum = 0
5        # Track minimum sum subarray (Kadane's algorithm variant)
6        min_sum = 0
7        # Track the maximum absolute sum found so far
8        max_absolute = 0
9      
10        for num in nums:
11            # Update max_sum: either extend current positive sum or start fresh from current number
12            max_sum = max(max_sum, 0) + num
13            # Update min_sum: either extend current negative sum or start fresh from current number
14            min_sum = min(min_sum, 0) + num
15            # Update answer with the maximum of current answer, max_sum, or absolute value of min_sum
16            max_absolute = max(max_absolute, max_sum, abs(min_sum))
17      
18        return max_absolute
19
1class Solution {
2    public int maxAbsoluteSum(int[] nums) {
3        // Track maximum positive sum ending at current position (Kadane's algorithm for max)
4        int maxEndingHere = 0;
5      
6        // Track minimum negative sum ending at current position (Kadane's algorithm for min)
7        int minEndingHere = 0;
8      
9        // Store the maximum absolute sum found so far
10        int maxAbsoluteSum = 0;
11      
12        // Iterate through each element in the array
13        for (int currentNum : nums) {
14            // Update max sum: either extend previous positive sum or start fresh from current
15            maxEndingHere = Math.max(maxEndingHere, 0) + currentNum;
16          
17            // Update min sum: either extend previous negative sum or start fresh from current
18            minEndingHere = Math.min(minEndingHere, 0) + currentNum;
19          
20            // Update result with the larger of current max sum or absolute value of min sum
21            maxAbsoluteSum = Math.max(maxAbsoluteSum, Math.max(maxEndingHere, Math.abs(minEndingHere)));
22        }
23      
24        return maxAbsoluteSum;
25    }
26}
27
1class Solution {
2public:
3    int maxAbsoluteSum(vector<int>& nums) {
4        // maxSum tracks the maximum subarray sum ending at current position
5        int maxSum = 0;
6      
7        // minSum tracks the minimum subarray sum ending at current position  
8        int minSum = 0;
9      
10        // result stores the maximum absolute sum found so far
11        int result = 0;
12      
13        // Iterate through each element in the array
14        for (int& num : nums) {
15            // Update maximum subarray sum using Kadane's algorithm
16            // Reset to 0 if previous sum was negative, then add current element
17            maxSum = max(maxSum, 0) + num;
18          
19            // Update minimum subarray sum (similar to Kadane's but for minimum)
20            // Reset to 0 if previous sum was positive, then add current element
21            minSum = min(minSum, 0) + num;
22          
23            // Update result with the maximum of:
24            // - current result
25            // - current maximum subarray sum
26            // - absolute value of current minimum subarray sum
27            result = max({result, maxSum, abs(minSum)});
28        }
29      
30        return result;
31    }
32};
33
1/**
2 * Finds the maximum absolute sum of any subarray
3 * Uses Kadane's algorithm variant to track both maximum and minimum subarray sums
4 * @param nums - Array of integers
5 * @returns Maximum absolute sum of any subarray
6 */
7function maxAbsoluteSum(nums: number[]): number {
8    // Track maximum sum ending at current position (for positive sums)
9    let maxSumEndingHere: number = 0;
10  
11    // Track minimum sum ending at current position (for negative sums)
12    let minSumEndingHere: number = 0;
13  
14    // Track the maximum absolute sum found so far
15    let maxAbsSum: number = 0;
16  
17    // Iterate through each number in the array
18    for (const currentNum of nums) {
19        // Update max sum: either extend previous positive sum or start fresh from current number
20        maxSumEndingHere = Math.max(maxSumEndingHere, 0) + currentNum;
21      
22        // Update min sum: either extend previous negative sum or start fresh from current number
23        minSumEndingHere = Math.min(minSumEndingHere, 0) + currentNum;
24      
25        // Update result with the maximum of:
26        // 1. Current maximum absolute sum
27        // 2. Current maximum positive sum
28        // 3. Absolute value of current minimum negative sum
29        maxAbsSum = Math.max(maxAbsSum, maxSumEndingHere, -minSumEndingHere);
30    }
31  
32    return maxAbsSum;
33}
34

Time and Space Complexity

The time complexity is O(n), where n is the length of the array nums. This is because the algorithm iterates through the array exactly once, performing constant-time operations (max, min, abs, and arithmetic operations) for each element.

The space complexity is O(1), as the algorithm only uses a fixed amount of extra space regardless of the input size. It maintains three variables (f, g, and ans) that store intermediate results, and these variables do not grow with the size of the input array.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

Pitfall 1: Forgetting to Consider Both Positive and Negative Sums

The Problem: A common mistake is to only track the maximum sum subarray and take its absolute value, missing cases where the minimum (most negative) sum subarray actually has a larger absolute value.

Example of Incorrect Approach:

def maxAbsoluteSum(self, nums: List[int]) -> int:
    max_sum = 0
    current_sum = 0
  
    for num in nums:
        current_sum = max(current_sum + num, num, 0)
        max_sum = max(max_sum, abs(current_sum))
  
    return max_sum

This would fail for nums = [2, -5, 1, -4, 3, -2] where the minimum sum subarray [-5, 1, -4] has sum -8 and absolute value 8, which is larger than any positive subarray sum.

Solution: Always track both the maximum and minimum sums simultaneously, as shown in the correct implementation.

Pitfall 2: Incorrect State Transition Logic

The Problem: Misunderstanding how to update the maximum and minimum sums can lead to incorrect results. A common error is:

# INCORRECT
max_sum = max(max_sum + num, num)  # Missing the "start fresh with 0" option
min_sum = min(min_sum + num, num)  # Missing the "start fresh with 0" option

This forces every subarray to include at least one element, which misses the case where it's better to "reset" and start a new subarray.

Solution: Use the correct transition formulas:

max_sum = max(max_sum, 0) + num  # Can choose to start fresh (0) or extend
min_sum = min(min_sum, 0) + num  # Can choose to start fresh (0) or extend

Pitfall 3: Not Initializing Variables Correctly

The Problem: Initializing max_sum or min_sum to the first element or to very large/small values:

# INCORRECT
max_sum = nums[0]  # Wrong initialization
min_sum = nums[0]  # Wrong initialization

This prevents the algorithm from correctly considering empty subarrays or properly resetting when needed.

Solution: Initialize both max_sum and min_sum to 0, representing empty subarrays before processing any elements.

Pitfall 4: Forgetting Edge Cases

The Problem: Not handling arrays with all positive or all negative numbers correctly, or forgetting that the empty subarray (sum = 0) is valid.

Example: For nums = [-1, -2, -3], the maximum absolute sum should be 6 (from subarray [-1, -2, -3]), not 3.

Solution: The algorithm naturally handles these cases by tracking both maximum and minimum sums and always considering the option to start fresh (empty subarray).

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

What's the output of running the following function using input 56?

1KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13    def dfs(path, res):
14        if len(path) == len(digits):
15            res.append(''.join(path))
16            return
17
18        next_number = digits[len(path)]
19        for letter in KEYBOARD[next_number]:
20            path.append(letter)
21            dfs(path, res)
22            path.pop()
23
24    res = []
25    dfs([], res)
26    return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2    '2', "abc".toCharArray(),
3    '3', "def".toCharArray(),
4    '4', "ghi".toCharArray(),
5    '5', "jkl".toCharArray(),
6    '6', "mno".toCharArray(),
7    '7', "pqrs".toCharArray(),
8    '8', "tuv".toCharArray(),
9    '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13    List<String> res = new ArrayList<>();
14    dfs(new StringBuilder(), res, digits.toCharArray());
15    return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19    if (path.length() == digits.length) {
20        res.add(path.toString());
21        return;
22    }
23    char next_digit = digits[path.length()];
24    for (char letter : KEYBOARD.get(next_digit)) {
25        path.append(letter);
26        dfs(path, res, digits);
27        path.deleteCharAt(path.length() - 1);
28    }
29}
30
1const KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13    let res = [];
14    dfs(digits, [], res);
15    return res;
16}
17
18function dfs(digits, path, res) {
19    if (path.length === digits.length) {
20        res.push(path.join(''));
21        return;
22    }
23    let next_number = digits.charAt(path.length);
24    for (let letter of KEYBOARD[next_number]) {
25        path.push(letter);
26        dfs(digits, path, res);
27        path.pop();
28    }
29}
30

Recommended Readings

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

Load More