# 53. Maximum Subarray

LeetCode Problem Link (opens new window)

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:

  • Input: [-2,1,-3,4,-1,2,1,-5,4]
  • Output: 6
  • Explanation: The subarray [4,-1,2,1] has the largest sum 6.

# Approach

# Brute Force

The brute force approach involves using a nested loop where the first loop sets the starting position and the second loop traverses the array to find the maximum value.

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int result = INT32_MIN;
        int count = 0;
        for (int i = 0; i < nums.size(); i++) { // Set starting position
            count = 0;
            for (int j = i; j < nums.size(); j++) { // Traverse from starting position i to find the maximum value
                count += nums[j];
                result = count > result ? count : result;
            }
        }
        return result;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • Time Complexity: O(n^2)
  • Space Complexity: O(1)

This brute force solution can barely pass in C++, but may not be feasible in other languages.

# Greedy Approach

Where does the greedy part apply?

If -2 and 1 are together, the starting point should definitely be from 1, as negative numbers only decrease the total sum—this is the greedy part of it!

Local optimal: If the current "cumulative sum" becomes negative, immediately abandon it and start recalculating the "cumulative sum" from the next element, because a negative sum will just reduce the overall sum when added to the next element.

Global optimal: Choose the maximum "cumulative sum".

In the case of local optimum, by continually recording the largest "cumulative sum", we can achieve a global optimum.

From a coding perspective: Traverse the nums, start accumulating count from the beginning, and if adding nums[i] results in a negative count, restart the accumulation from nums[i+1] because a negative count will just lower the total sum.

This is equivalent to constantly adjusting the starting position of the maximum subarray in the brute-force solution.

It might be asked: Don't we need to adjust the ending position of the interval to get the maximum "cumulative sum"?

The ending position is actually managed by keeping track of the maximum "cumulative sum" that can be updated in a similar manner, as shown in the following code:

if (count > result) result = count;
1

Thus, storing the maximum accumulated value acts as a way to adjust the termination position of the subarray.

As shown in the animation below:

53. Maximum Subarray

The red starting positions indicate when the greedy algorithm initiates counting when count is positive.

The following C++ code illustrates this (key points are commented):

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int result = INT32_MIN;
        int count = 0;
        for (int i = 0; i < nums.size(); i++) {
            count += nums[i];
            if (count > result) { // Accumulate the maximum value found in the interval (which seems to be equivalent to constantly determining the terminus of the maximum subarray)
                result = count;
            }
            if (count <= 0) count = 0; // Resets the starting point of the maximum subarray as a negative number would only lower the sum
        }
        return result;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • Time Complexity: O(n)
  • Space Complexity: O(1)

The problem does not specify the expected return value when the array is empty, so any return value can be acceptable in that case.

# Common Misconceptions

Misconception 1:

Many believe if the input cases consist entirely of -1, or all negative numbers, this greedy algorithm would result in 0. This is again a classic example of unreliable manual simulation—it's suggested to run the code to see what happens, which also illustrates why result is initialized with the smallest negative number.

Misconception 2:

When using a greedy algorithm to solve this problem, participants often confuse whether the starting point should be chosen when a negative number is encountered or when the continuous sum is negative.

The animation clarifies this: when encountering 4 and then -1, we still accumulate. Why?

Because the sum is still positive even after calculating 4 + -1, which would yield 3, and any positive sum can potentially increase the total sum. Thus, we maintain a positive continuous sum whenever possible.

Some may also worry whether omitting 4 as the maximum continuous sum is a possibility after subtracting -1.

Actually, it's not a concern because another variable, result, is kept to update the maximum continuous sum whenever a larger is found. It thus keeps track of 4, ensuring that intermediate sums like 3 do not affect the final result.

# Dynamic Programming

This problem can also be tackled using dynamic programming, which will be detailed in the dynamic programming section of the series. If you're eager to see the dynamic programming approach, you can directly reference here: Dynamic Programming Detailed Version (opens new window)

Here is my dynamic programming code, and those interested can attempt it in advance:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        vector<int> dp(nums.size(), 0); // dp[i] represents the maximum sum of the subarray including i
        dp[0] = nums[0];
        int result = dp[0];
        for (int i = 1; i < nums.size(); i++) {
            dp[i] = max(dp[i - 1] + nums[i], nums[i]); // State transition formula
            if (dp[i] > result) result = dp[i]; // result keeps track of the maximum value of dp[i]
        }
        return result;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • Time Complexity: O(n)
  • Space Complexity: O(n)

# Conclusion

The greedy idea behind this problem is not easy to come up with, proving that, although the theoretical foundation of greed incurs common sense, greed problems themselves are complex!

Subsequent greedy topics to be introduced are quite challenging, showing just how interesting the greedy algorithm is, so let's not underestimate its complexity!

# Other Language Versions

# Java

class Solution {
    public int maxSubArray(int[] nums) {
        if (nums.length == 1){
            return nums[0];
        }
        int sum = Integer.MIN_VALUE;
        int count = 0;
        for (int i = 0; i < nums.length; i++){
            count += nums[i];
            sum = Math.max(sum, count); // Accumulate the maximum value found in the interval
            if (count <= 0){
                count = 0; // Resets the starting point of the maximum subarray as a negative number only lowers the sum
            }
        }
       return sum;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// DP Method
class Solution {
    public int maxSubArray(int[] nums) {
        int ans = Integer.MIN_VALUE;
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        ans = dp[0];

        for (int i = 1; i < nums.length; i++){
            dp[i] = Math.max(dp[i-1] + nums[i], nums[i]);
            ans = Math.max(dp[i], ans);
        }

        return ans;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# Python

Brute Force

class Solution:
    def maxSubArray(self, nums):
        result = float('-inf')  # Initialize result to negative infinity
        count = 0
        for i in range(len(nums)):  # Set starting position
            count = 0
            for j in range(i, len(nums)):  # Traverse from starting position i to find the maximum value
                count += nums[j]
                result = max(count, result)  # Update maximum value
        return result
1
2
3
4
5
6
7
8
9
10

Greedy

class Solution:
    def maxSubArray(self, nums):
        result = float('-inf')  # Initialize result to negative infinity
        count = 0
        for i in range(len(nums)):
            count += nums[i]
            if count > result:  # Accumulate the maximum value found in the interval
                result = count
            if count <= 0:  # Resets the starting point of the maximum subarray as a negative number only lowers the sum
                count = 0
        return result
1
2
3
4
5
6
7
8
9
10
11

Dynamic Programming

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        dp = [0] * len(nums)
        dp[0] = nums[0]
        res = nums[0]
        for i in range(1, len(nums)):
            dp[i] = max(dp[i-1] + nums[i], nums[i])
            res = max(res, dp[i])
        return res
1
2
3
4
5
6
7
8
9

Dynamic Programming

class Solution:
    def maxSubArray(self, nums):
        if not nums:
            return 0
        dp = [0] * len(nums)    # dp[i] represents the maximum sum of the subarray including i
        dp[0] = nums[0]
        result = dp[0]
        for i in range(1, len(nums)):
            dp[i] = max(dp[i-1]+nums[i], nums[i])   # State transition formula
            if dp[i] > result:
                result = dp[i]                      # result keeps track of the maximum value of dp[i]
        return result
1
2
3
4
5
6
7
8
9
10
11
12

Optimized Dynamic Programming

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        max_sum = float("-inf") # Initialize result to negative infinity for comparison to obtain maximum value
        current_sum = 0         # Initialize current continuous sum

        for num in nums:

            # Update current continuous sum
            # If adding the current number to the previous continuous sum doesn't surpass the current number, the prior continuous is negative and a fresh calculation is necessary
            current_sum = max(current_sum+num, num) 
            max_sum = max(max_sum, current_sum) # Update result

        return max_sum
1
2
3
4
5
6
7
8
9
10
11
12
13

# Go

Greedy

func maxSubArray(nums []int) int {
    max := nums[0]
    count := 0

    for i := 0; i < len(nums); i++{
        count += nums[i]
        if count > max{
            max = count
        }
        if count < 0 {
            count = 0
        }
    } 
    return max
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Dynamic Programming

func maxSubArray(nums []int) int {
    maxSum := nums[0]
    for i := 1; i < len(nums); i++ {
        if nums[i] + nums[i-1] > nums[i] {
            nums[i] += nums[i-1]
        }
        if nums[i] > maxSum {
            maxSum = nums[i]
        }
    }
    return maxSum
}
1
2
3
4
5
6
7
8
9
10
11
12

# Rust

pub fn max_sub_array(nums: Vec<i32>) -> i32 {
    let mut max_sum = i32::MIN;
    let mut curr = 0;
    for n in nums.iter() {
        curr += n;
        max_sum = max_sum.max(curr);
        curr = curr.max(0);
    }
    max_sum
}
1
2
3
4
5
6
7
8
9
10

# JavaScript:

var maxSubArray = function(nums) {
    let result = -Infinity
    let count = 0
    for(let i = 0; i < nums.length; i++) {
        count += nums[i]
        if(count > result) {
            result = count
        }
        if(count < 0) {
            count = 0
        }
    }
    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# C:

Greedy:

int maxSubArray(int* nums, int numsSize){
    int maxVal = INT_MIN;
    int subArrSum = 0;

    int i;
    for(i = 0; i < numsSize; ++i) {
        subArrSum += nums[i];
        // Update the result if the current local sum is greater than the previous maximum result
        maxVal = subArrSum > maxVal ? subArrSum : maxVal;
        // Reset sub-array calculation when the local sum turns negative
        subArrSum = subArrSum < 0 ? 0 : subArrSum;
    }

    return maxVal;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Dynamic Programming:

/**
 * Dynamic programming approach:
 * 1. dp Array: `dp[i]` stores the maximum subarray sum up to i
 * 2. Recurrence Relation: `dp[i] = max(dp[i-1] + nums[i], nums[i])`
    If `dp[i-1]` is negative, it has no benefit for the final result. Thus `dp[i]` takes `nums[i]`.
 * 3. Initialize dp array: `dp[0]` has the maximum subarray sum of `nums[0]`
 * 4. Traverse order: Iterate from the beginning
 */

#define max(a, b) (((a) > (b)) ? (a) : (b))

int maxSubArray(int* nums, int numsSize){
    int dp[numsSize];
    // Maximum subarray sum for `dp[0]` is `nums[0]`
    dp[0] = nums[0];
    // Return `nums[0]` if `numsSize` is 1
    int subArrSum = nums[0];

    int i;
    for(i = 1; i < numsSize; ++i) {
        dp[i] = max(dp[i - 1] + nums[i], nums[i]);

        // If `dp[i]` is greater than previously recorded maximum value, update it
        if(dp[i] > subArrSum)
            subArrSum = dp[i];
    }

    return subArrSum;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# TypeScript

Greedy

function maxSubArray(nums: number[]): number {
  let curSum: number = 0;
  let resMax: number = -Infinity;
  for (let i = 0, length = nums.length; i < length; i++) {
    curSum += nums[i];
    resMax = Math.max(curSum, resMax);
    if (curSum < 0) curSum = 0;
  }
  return resMax;
}
1
2
3
4
5
6
7
8
9
10

Dynamic Programming

// Dynamic Programming
function maxSubArray(nums: number[]): number {
  const length = nums.length;
  if (length === 0) return 0;
  const dp: number[] = [];
  dp[0] = nums[0];
  let resMax: number = nums[0];
  for (let i = 1; i < length; i++) {
    dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
    resMax = Math.max(resMax, dp[i]);
  }
  return resMax;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# Scala

Greedy

object Solution {
  def maxSubArray(nums: Array[Int]): Int = {
    var result = Int.MinValue
    var count = 0
    for (i <- nums.indices) {
      count += nums(i)  // Accumulate count
      if (count > result) result = count  // Record maximum value
      if (count <= 0) count = 0  // Once the count is negative, reset it to zero
    }
    result
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

Dynamic Programming

object Solution {
  def maxSubArray(nums: Array[Int]): Int = {
    var dp = new Array[Int](nums.length)
    var result = nums(0)
    dp(0) = nums(0)
    for (i <- 1 until nums.length) {
      dp(i) = math.max(nums(i), dp(i - 1) + nums(i))
      result = math.max(result, dp(i))  // Update maximum value
    }
    result
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

# C#

Greedy

public class Solution
{
    public int MaxSubArray(int[] nums)
    {
        int res = Int32.MinValue;
        int count = 0;
        for (int i = 0; i < nums.Length; i++)
        {
            count += nums[i];
            res = Math.Max(res, count);
            if (count < 0) count = 0;
        }
        return res;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Last updated:: 9/4/2025, 3:19:38 PM
Copyright © 2025 keetcoder