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
35
struct T {
  // the sum of the subarray starting from the first number
  int maxSubarraySumLeft;
  // the sum of the subarray ending in the last number
  int maxSubarraySumRight;
  int maxSubarraySum;
  int sum;
};

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 t1 = divideAndConquer(nums, l, m);
    const T t2 = divideAndConquer(nums, m + 1, r);

    const int maxSubarraySumLeft =
        max(t1.maxSubarraySumLeft, t1.sum + t2.maxSubarraySumLeft);
    const int maxSubarraySumRight =
        max(t1.maxSubarraySumRight + t2.sum, t2.maxSubarraySumRight);
    const int maxSubarraySum =
        max({t1.maxSubarraySumRight + t2.maxSubarraySumLeft, t1.maxSubarraySum,
             t2.maxSubarraySum});
    const int sum = t1.sum + t2.sum;
    return {maxSubarraySumLeft, maxSubarraySumRight, maxSubarraySum, sum};
  }
};
 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
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 t1 = divideAndConquer(nums, l, m);
    final T t2 = divideAndConquer(nums, m + 1, r);

    final int maxSubarraySumLeft = Math.max(t1.maxSubarraySumLeft, t1.sum + t2.maxSubarraySumLeft);
    final int maxSubarraySumRight =
        Math.max(t1.maxSubarraySumRight + t2.sum, t2.maxSubarraySumRight);
    final int maxSubarraySum = Math.max(t1.maxSubarraySumRight + t2.maxSubarraySumLeft,
                                        Math.max(t1.maxSubarraySum, t2.maxSubarraySum));
    final int sum = t1.sum + t2.sum;
    return new T(maxSubarraySumLeft, maxSubarraySumRight, maxSubarraySum, sum);
  }

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


@dataclass(frozen=True)
class T:
  # 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
  summ: 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
      t1 = divideAndConquer(l, m)
      t2 = divideAndConquer(m + 1, r)

      maxSubarraySumLeft = max(t1.maxSubarraySumLeft,
                               t1.summ + t2.maxSubarraySumLeft)
      maxSubarraySumRight = max(
          t1.maxSubarraySumRight + t2.summ, t2.maxSubarraySumRight)
      maxSubarraySum = max(t1.maxSubarraySumRight +
                           t2.maxSubarraySumLeft, t1.maxSubarraySum, t2.maxSubarraySum)
      summ = t1.summ + t2.summ
      return T(maxSubarraySumLeft, maxSubarraySumRight, maxSubarraySum, summ)

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