Skip to content
← All posts

Maximum Ascending Subarray Sum: Greedy Scan Pattern

5 min read
leetcodeproblemeasyarrays

Given an array of positive integers nums, return the maximum possible sum of an ascending subarray in nums. A subarray is ascending if for every pair of consecutive elements, the later one is strictly greater than the earlier one.

This is LeetCode 1800: Maximum Ascending Subarray Sum, and it is one of the cleanest examples of the greedy scan pattern. You walk through the array once, maintaining a running sum that you either extend or reset. No sorting, no extra space, no tricks.

10020130253104505sum = 60sum = 65 (max)
Input: [10, 20, 30, 5, 10, 50]. Two ascending subarrays: [10, 20, 30] with sum 60 and [5, 10, 50] with sum 65.

Why this problem matters

Maximum Ascending Subarray Sum is a gentle warm-up, but the pattern it teaches is everywhere. Any time you need to find an optimal contiguous segment under some condition, you will reach for the same structure: maintain a running value, decide at each step whether to extend or restart, and track the best you have seen. The same skeleton drives Maximum Subarray (Kadane's algorithm), stock profit problems, and many sliding window variants.

Getting this pattern into muscle memory on an easy problem means you will not fumble the mechanics when a medium or hard problem demands it.

The key insight

Because the subarray must be strictly ascending, you only have two cases at each index:

  1. Extend: if nums[i] is strictly greater than nums[i - 1], the ascending run continues. Add nums[i] to your running sum.
  2. Reset: otherwise, the ascending run is broken. Start a fresh run at nums[i].

After each step, compare your running sum against the best you have recorded. That is the entire algorithm. One pass, one variable for the current sum, one variable for the max.

The solution

def maxAscendingSum(nums):
    current_sum = nums[0]
    max_sum = nums[0]

    for i in range(1, len(nums)):
        if nums[i] > nums[i - 1]:
            current_sum += nums[i]
        else:
            current_sum = nums[i]
        max_sum = max(max_sum, current_sum)

    return max_sum

Walk through it line by line:

  1. Initialize current_sum and max_sum to nums[0]. The first element on its own is a valid ascending subarray.
  2. For each subsequent element, check whether it continues the ascending trend. If nums[i] is strictly greater than its predecessor, add it to the running sum. If not, reset the running sum to just this element.
  3. After every update, check if current_sum beats max_sum. If so, update it.
  4. Return max_sum at the end.

The comparison is strictly greater, not greater-or-equal. Two equal neighbors break the ascending run. This is a common misread of the problem statement that leads to wrong answers on edge cases like [1, 1, 1].

Visual walkthrough

Step 1: i = 0, nums[0] = 10. Initialize.

10020130253104505i

current_sum = 10, max_sum = 10. Start with current_sum = 10 and max_sum = 10.

Step 2: i = 1, nums[1] = 20. 20 > 10, so extend.

10020130253104505i

current_sum = 30, max_sum = 30. Still ascending. current_sum = 10 + 20 = 30. max_sum = 30.

Step 3: i = 2, nums[2] = 30. 30 > 20, so extend.

10020130253104505i

current_sum = 60, max_sum = 60. Still ascending. current_sum = 30 + 30 = 60. max_sum = 60.

Step 4: i = 3, nums[3] = 5. 5 is not > 30, so reset.

10020130253104505i

current_sum = 5, max_sum = 60. Sequence breaks. Reset current_sum = 5. max_sum stays 60.

Step 5: i = 4, nums[4] = 10. 10 > 5, so extend.

10020130253104505i

current_sum = 15, max_sum = 60. Ascending again. current_sum = 5 + 10 = 15. max_sum stays 60.

Step 6: i = 5, nums[5] = 50. 50 > 10, so extend.

10020130253104505i

current_sum = 65, max_sum = 65. current_sum = 15 + 50 = 65. New max_sum = 65. Done! Answer is 65.

The answer is 65, from the ascending subarray [5, 10, 50].

Notice that the first ascending run [10, 20, 30] has a sum of 60, which looks promising. But the second run [5, 10, 50] edges it out with 65. The reset at index 3 is the critical moment: 5 is not greater than 30, so we drop everything and start fresh. Without that reset, we would be adding 5 to a sum that includes non-ascending pairs.

Complexity analysis

ApproachTimeSpace
Greedy single passO(n)O(1)

Time: O(n). You visit each element exactly once. Each visit does O(1) work: one comparison and one addition or assignment.

Space: O(1). Two variables (current_sum and max_sum), regardless of input size.

This is optimal. You must examine every element at least once because any element could be part of the best ascending subarray, so O(n) time is the floor.

The building blocks

1. Greedy scan with extend-or-reset

This is the same skeleton behind Kadane's algorithm for Maximum Subarray. In Kadane's, you decide whether to extend or restart based on whether the running sum has gone negative. Here, you decide based on whether the sequence is still ascending. Different condition, same structure: maintain a running value, choose extend or reset at each step, track the global best.

2. Running max

You maintain max_sum as you iterate, updating it whenever current_sum beats the current record. This is the same running-extremum idea from Best Time to Buy and Sell Stock, where you track a running minimum. Here you track a running maximum. The concept is identical: one variable that captures the best value seen so far, updated in constant time at each step.

Edge cases

Before submitting, make sure your solution handles these:

  • Single element like [42]: the answer is 42. There is only one subarray.
  • All equal like [5, 5, 5]: no pair is strictly ascending, so every element is its own subarray. Answer is 5.
  • Strictly descending like [30, 20, 10]: same idea. Every run is length 1. Answer is 30.
  • Entirely ascending like [1, 2, 3, 4]: the whole array is one ascending subarray. Answer is 10.
  • Reset then big jump like [100, 1, 1000]: the run [100] has sum 100, the run [1, 1000] has sum 1001. Make sure the reset does not cause you to miss the big jump.

The greedy scan handles all of these with no special cases.

From understanding to recall

You have just read through the extend-or-reset logic and it feels obvious. But during an interview, you will not have this page in front of you. Under time pressure, small details trip people up: is the comparison strict or non-strict? Do I initialize to nums[0] or to 0? Do I reset to nums[i] or to 0?

Spaced repetition drills these details until they are automatic. Instead of solving this problem once and forgetting the initialization logic in two weeks, you write the code from scratch at increasing intervals. After a few reps, the pattern is locked in.

The extend-or-reset scan is one of roughly 60 reusable building blocks that cover hundreds of LeetCode problems. Drilling them individually with spaced repetition is far more efficient than grinding problems one at a time and hoping the patterns stick.

Related posts