# 53. Maximum Subarray

Reference: LeetCode

Difficulty: Easy

My Post: Easy-Understand Java Solutions with Explanations (B-F, Divide-And-Conquer, DP)

## Problem

Given an integer array

`nums`

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

**Example:**

1 | Input: [-5] |

**Follow up:** If you have figured out the $O(N)$ solution, try coding another solution using the divide and conquer approach, which is more subtle.

## Analysis

### Most Stupid Solution

For each element, we construct all possible subarrays starting from this element. Totally there are at most $N^2$ subarrays. Also, calculating the sum of each subarray takes $O(N)$.

1 | public int maxSubArray(int[] nums) { |

**Time:** $O(N^3)$**Space:** $O(1)$

### Brute-Force

Why did you calculate the sum separately?

**Note:** In the inner loop, start from `i + 1`

. Don’t initialize `sum`

as $0$ and start from `i`

.

1 | public int maxSubArray(int[] nums) { |

**Time:** $O(N^2)$**Space:** $O(1)$

### Divide and Conquer

Divide-and-conquer consider 3 cases:

**Case 1:**Subarray in the left half ->`leftSum`

**Case 2:**Subarray in the right half ->`rightSum`

**Case 3:**Subarray crosses the middle ->`crossSum`

We need to compare three max values: `leftSum`

, `rightSum`

, and `crossSum`

. By constructing the `crossSum`

, we propagate from the right-end of the left subarray `[lo, mid]`

and from the left-end of the right subarray `[mid + 1, hi]`

. In each direction, we are continuously updating the maximum sum.

1 | // Example |

**BTW, Index lo/hi/mid Caveat:**

Write the condition as `if (lo == hi)`

(stops at one element) or `if (lo >= hi)`

(stops at $0$ element). Why?

Write the subproblem as `[lo, mid]`

and `[mid + 1, hi]`

, which is not like binary search (`hi = mid - 1`

and `lo = mid + 1`

).

1 | public int maxSubArray(int[] nums) { |

Another version, initialize sums and max values as the first element.

1 | private int crossSum(int[] nums, int lo, int hi, int mid) { |

**Time:** $O(N\log{N})$ since $T(N) = 2T(N/2) + O(N)$.**Space:** $O(\log{N})$

### DP

Suppose we know the maximum subarray ending at $i$ (inclusive). We denote `SUM(i)`

as the maximum sum of a subarray ending at index $i$ and denote `OPT(i)`

as the maximum sum in the subarray $[0, i]$. Our final result is `OPT(n - 1)`

. (notice the difference since it is very trivial)

For an element `nums[i]`

, we have two choices: Appending it to a previous subarray `SUM(i - 1)`

or start a new subarray from itself. Then we can write the recurrence for `SUM(i)`

and `OPT(i)`

as follows:

`SUM(i)`

= max(`SUM(i - 1) + nums[i]`

, `nums[i]`

)`OPT(i)`

= max(`OPT(i - 1)`

, `SUM(i)`

).

Note: `OPT`

is updated when a larger `SUM[i]`

is discovered.

The initial values are `SUM(0) = nums[0]`

and `OPT(0) = nums[0]`

. We can do it in one pass. So here is the code:

1 | public int maxSubArray(int[] nums) { |

Since `SUM(i)`

and `OPT(i)`

could be calculated by the previous values, we don’t need arrays of size $n$ to store all information. Here is the code that reduces the space complexity:

1 | public int maxSubArray(int[] nums) { |

**Time:** $O(N)$**Space:** $O(1)$