Skip to content

53. Maximum Subarray 👍

Approach 1: 1D DP

  • Time: $O(n)$
  • Space: $O(n)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Solution {
 public:
  int maxSubArray(vector<int>& nums) {
    // dp[i] := the maximum sum subarray ending in i
    vector<int> dp(nums.size());

    dp[0] = nums[0];
    for (int i = 1; i < nums.size(); ++i)
      dp[i] = max(nums[i], dp[i - 1] + nums[i]);

    return ranges::max(dp);
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Solution {
  public int maxSubArray(int[] nums) {
    // dp[i] := the maximum sum subarray ending in i
    int[] dp = new int[nums.length];

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

    return Arrays.stream(dp).max().getAsInt();
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Solution:
  def maxSubArray(self, nums: list[int]) -> int:
    # dp[i] := the maximum sum subarray ending in i
    dp = [0] * len(nums)

    dp[0] = nums[0]
    for i in range(1, len(nums)):
      dp[i] = max(nums[i], dp[i - 1] + nums[i])

    return max(dp)

Approach 2: $O(1)$ DP

  • Time: $O(n)$
  • Space: $O(1)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution {
 public:
  int maxSubArray(vector<int>& nums) {
    int ans = INT_MIN;
    int sum = 0;

    for (const int num : nums) {
      sum = max(num, sum + num);
      ans = max(ans, sum);
    }

    return ans;
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Solution {
  public int maxSubArray(int[] nums) {
    int ans = Integer.MIN_VALUE;
    int sum = 0;

    for (final int num : nums) {
      sum = Math.max(num, sum + num);
      ans = Math.max(ans, sum);
    }

    return ans;
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Solution:
  def maxSubArray(self, nums: list[int]) -> int:
    ans = -math.inf
    summ = 0

    for num in nums:
      summ = max(num, summ + num)
      ans = max(ans, summ)

    return ans

Approach 3: Divide and Conquer

  • Time: $O(n\log n)$
  • Space: $O(\log n)$
 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
30
31
32
33
34
struct T {
  int sum;
  // the sum of the subarray starting from the first number
  int maxSubarraySumPrefix;
  // the sum of the subarray ending in the last number
  int maxSubarraySumSuffix;
  int maxSubarraySum;
};

class Solution {
 public:
  int maxSubArray(vector<int>& nums) {
    return divideAndConquer(nums, 0, nums.size() - 1).maxSubarraySum;
  }

 private:
  T divideAndConquer(const vector<int>& nums, int l, int r) {
    if (l == r)
      return {nums[l], nums[l], nums[l], nums[l]};
    const int m = (l + r) / 2;
    const T left = divideAndConquer(nums, l, m);
    const T right = divideAndConquer(nums, m + 1, r);
    return T{
        .sum = left.sum + right.sum,
        .maxSubarraySumPrefix = max(left.maxSubarraySumPrefix,
                                    left.sum + right.maxSubarraySumPrefix),
        .maxSubarraySumSuffix = max(right.maxSubarraySumSuffix,
                                    right.sum + left.maxSubarraySumSuffix),
        .maxSubarraySum =
            max({left.maxSubarraySum, right.maxSubarraySum,
                 left.maxSubarraySumSuffix + right.maxSubarraySumPrefix}),
    };
  }
};
 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
class Solution {
  public int maxSubArray(int[] nums) {
    return divideAndConquer(nums, 0, nums.length - 1).maxSubarraySum;
  }

  private T divideAndConquer(int[] nums, int l, int r) {
    if (l == r)
      return new T(nums[l], nums[l], nums[l], nums[l]);
    final int m = (l + r) / 2;
    final T left = divideAndConquer(nums, l, m);
    final T right = divideAndConquer(nums, m + 1, r);
    final int maxSubarraySumPrefix =
        Math.max(left.maxSubarraySumPrefix, left.sum + right.maxSubarraySumPrefix);
    final int maxSubarraySumSuffix =
        Math.max(left.maxSubarraySumSuffix + right.sum, right.maxSubarraySumSuffix);
    final int maxSubarraySum = Math.max(left.maxSubarraySumSuffix + right.maxSubarraySumPrefix,
                                        Math.max(left.maxSubarraySum, right.maxSubarraySum));
    final int sum = left.sum + right.sum;
    return new T(sum, maxSubarraySumPrefix, maxSubarraySumSuffix, maxSubarraySum);
  }

  private record T(int sum,
                   // the sum of the subarray starting from the first number
                   int maxSubarraySumPrefix,
                   // the sum of the subarray ending in the last number
                   int maxSubarraySumSuffix, //
                   int maxSubarraySum) {}
}
 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
30
31
from dataclasses import dataclass


@dataclass(frozen=True)
class T:
  summ: int
  # the sum of the subarray starting from the first number
  maxSubarraySumLeft: int
  # the sum of the subarray ending in the last number
  maxSubarraySumRight: int
  maxSubarraySum: int


class Solution:
  def maxSubArray(self, nums: list[int]) -> int:
    def divideAndConquer(l: int, r: int) -> T:
      if l == r:
        return T(nums[l], nums[l], nums[l], nums[l])
      m = (l + r) // 2
      left = divideAndConquer(l, m)
      right = divideAndConquer(m + 1, r)
      maxSubarraySumLeft = max(left.maxSubarraySumLeft,
                               left.summ + right.maxSubarraySumLeft)
      maxSubarraySumRight = max(
          left.maxSubarraySumRight + right.summ, right.maxSubarraySumRight)
      maxSubarraySum = max(left.maxSubarraySumRight + right.maxSubarraySumLeft,
                           left.maxSubarraySum, right.maxSubarraySum)
      summ = left.summ + right.summ
      return T(summ, maxSubarraySumLeft, maxSubarraySumRight, maxSubarraySum)

    return divideAndConquer(0, len(nums) - 1).maxSubarraySum