文章目录
Maximum Subarray
Description
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: [4,-1,2,1] has the largest sum = 6.
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.
Solution
1. Kadane’s algorithms takes O(n) time.
对于第i
个数组元素,对应子数组以第i
个元素结尾为[M, nums[i]]
或[nums[i]]
,其中M
为以第i-1
数组元素结束的最大子数组。
如果sum(M)+nums[i] > nums[i]
,那么以第i
个数组元素结尾的子数组为[M, nums[i]]
,如果sum(M)+nums[i] <= nums[i]
,那么以第i
个数组元素结尾的子数组为[nums[i]]
。
遍历每一个数组元素,计算以该数组元素结尾的最大子数组的和,并且在遍历过程中,保留其最大值max_global
。
Time complexity: O(n)
class Solution {
public int maxSubArray(int[] nums) {
int max_global = nums[0];
int max_curr = nums[0];
for (int i = 1; i < nums.length; i++) {
max_curr = Math.max(max_curr+nums[i], nums[i]);
max_global = Math.max(max_curr, max_global);
}
return max_global;
}
}
2. Divide and Conquer
- 将数组分为两个子数组, divide
- 返回下列三项中的最大值:
- 左半部分数组的 Maximum subarray sum(递归调用), conquer
- 右半部分数组的 Maximum subarray sum (递归调用), conquer
- 子数组包括中间的分割点的 Maximum subarray sum (linear time), combine
Time Complexity: T[n] = 2T[n/2] + O(n) --> O(nlg(n))
class Solution {
public int maxSubArray(int[] nums) {
return maxSubArray(nums, 0, nums.length-1);
}
private int maxSubArray(int[] nums, int lo, int hi) {
// Base case: when only one element, return it
if (lo == hi)
return nums[lo];
// Find the middle point
int mid = (lo + hi) / 2;
/* Return maximum of following three possible cases:
a) Maximum subarray sum in left half
b) Maximum subarray sum in right half
c) Maximum subarray sum such that the subarray crosses the midpoint */
return Math.max(Math.max(maxSubArray(nums, lo, mid), maxSubArray(nums, mid+1, hi)), maxCrossingSum(nums, lo, mid, hi));
}
private int maxCrossingSum(int[] nums, int lo, int mid, int hi) {
// go from mid to lo, find the largest subarray sum
int leftMaxSum = Integer.MIN_VALUE, leftSum = 0;
for (int i = mid; i >= lo; i--) {
leftSum += nums[i];
leftMaxSum = Math.max(leftSum, leftMaxSum);
}
// go from mid to hi, find the largest subarray sum
int rightMaxSum = Integer.MIN_VALUE, rightSum = 0;
for (int i = mid+1; i <= hi; i++) {
rightSum += nums[i];
rightMaxSum = Math.max(rightSum, rightMaxSum);
}
return leftMaxSum + rightMaxSum;
}
}