Skip to content

53. Maximum Subarray 👍

Approach 1: Gready

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

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

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

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

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

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

    return ans

Approach 2: 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
struct T {
  int left;   // sum of the subarray w/ max sum (starting from the first num)
  int right;  // sum of the subarray w/ max sum (ending at the the last num)
  int mid;    // sum of the subarray w/ max sum
  int sum;    // sum of the whole array
};

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

 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 left = max(t1.left, t1.sum + t2.left);
    const int right = max(t1.right + t2.sum, t2.right);
    const int mid = max({t1.right + t2.left, t1.mid, t2.mid});
    const int sum = t1.sum + t2.sum;
    return {left, right, mid, 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
class T {
  public int left;  // sum of the subarray w/ max sum (starting from the first num)
  public int right; // sum of the subarray w/ max sum (ending at the the last num)
  public int mid;   // sum of the subarray w/ max sum
  public int sum;   // sum of the whole array
  public T(int left, int right, int mid, int sum) {
    this.left = left;
    this.right = right;
    this.mid = mid;
    this.sum = sum;
  }
}

class Solution {
  public int maxSubArray(int[] nums) {
    return divideAndConquer(nums, 0, nums.length - 1).mid;
  }

  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 left = Math.max(t1.left, t1.sum + t2.left);
    final int right = Math.max(t1.right + t2.sum, t2.right);
    final int mid = Math.max(t1.right + t2.left, Math.max(t1.mid, t2.mid));
    final int sum = t1.sum + t2.sum;
    return new T(left, right, mid, sum);
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Solution:
  def maxSubArray(self, nums: List[int]) -> int:
    def divideAndConquer(l: int, r: int) -> Tuple[int, int, int, int]:
      if l == r:
        return nums[l], nums[l], nums[l], nums[l]

      m = (l + r) // 2
      t1 = divideAndConquer(l, m)
      t2 = divideAndConquer(m + 1, r)

      left = max(t1[0], t1[3] + t2[0])
      right = max(t1[1] + t2[3], t2[1])
      mid = max(t1[1] + t2[0], max(t1[2], t2[2]))
      summ = t1[3] + t2[3]
      return left, right, mid, summ

    return divideAndConquer(0, len(nums) - 1)[2]

Approach 3: DP

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

    for (int i = 0; i < nums.size(); ++i)
      if (i > 0 && dp[i - 1] > 0)
        dp[i] = dp[i - 1] + nums[i];
      else
        dp[i] = nums[i];

    return *max_element(begin(dp), end(dp));
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution {
  public int maxSubArray(int[] nums) {
    // dp[i] := max sum subarray ending w/ nums[i]
    int[] dp = new int[nums.length];

    for (int i = 0; i < nums.length; ++i)
      if (i > 0 && dp[i - 1] > 0)
        dp[i] = dp[i - 1] + nums[i];
      else
        dp[i] = nums[i];

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

    for i, num in enumerate(nums):
      if i > 0 and dp[i - 1] > 0:
        dp[i] = dp[i - 1] + num
      else:
        dp[i] = num

    return max(dp)