题目:
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [−2,1,−3,4,−1,2,1,−5,4]
,
the contiguous subarray [4,−1,2,1]
has the largest sum = 6
.
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
思路一:从前向后。如果前面的和已经小于0了,那么抛弃前面的部分,从当前部分重新计算,因为如果sum{A[i], ... , A[j]} < 0,那么A[i] + ... + A[j] + A[j+1] + ... + A[k] 总是小于 A[j] + A[j+1] + ... + A[k] 的,所以抛弃前面的段。通过这样的做法,我们可以得到很多subarray,实时更新最大值即可。
class Solution {
public:
int maxSubArray(int A[], int n) {
int current_sum = A[0];
int max_sum = A[0];
for (int i = 1; i < n; ++i) {
current_sum = current_sum > 0 ? current_sum + A[i] : A[i];
max_sum = max_sum > current_sum ? max_sum : current_sum;
}
return max_sum;
}
};
总结:复杂度为O(n).
思路二:Divide and conquer.
Leetcode上建议了这种做法,实际上复杂度更高,只是为了体现一种思想。我们知道,如果将一个数组劈成两半,那么最大和的子数组可能在左边,在右边,或者是包含pivot的一段数组。将数组持续拆分,直到拆分到只剩下一个元素,这时最大和子数组必然就是这个元素了,可以直接返回。然后利用上面的规律,和拆分后返回的结果,逐步合并,最后得到全局的最大和子数组。整个过程有点像merge sort.
class Solution {
public:
int max_subarray_helper(const int A[], int lower_bound, int upper_bound) {
if (lower_bound == upper_bound) return A[lower_bound];
int mid = (lower_bound + upper_bound) / 2;
int left_max = max_subarray_helper(A, lower_bound, mid);
int right_max = max_subarray_helper(A, mid + 1, upper_bound);
int left_sum = A[mid];
int left_sum_max = A[mid];
for (int i = mid - 1; i >= lower_bound; --i) {
left_sum += A[i];
left_sum_max = left_sum_max > left_sum ? left_sum_max : left_sum;
}
int right_sum = A[mid+1];
int right_sum_max = A[mid+1];
for (int i = mid + 2; i <= upper_bound; ++i) {
right_sum += A[i];
right_sum_max = right_sum_max > right_sum ? right_sum_max : right_sum;
}
int temp_max = left_max > right_max ? left_max : right_max;
return temp_max > (left_sum_max + right_sum_max) ? temp_max : left_sum_max + right_sum_max;
}
int maxSubArray(int A[], int n) {
return max_subarray_helper(A, 0, n - 1);
}
};
总结:将拆分过程看成一个二叉树,树的root是长度为n的数组,叶子为每一个元素,树的高度为logn. 在merge的过程中,每一层都要对每一个元素遍历一遍,因此每一层的复杂度为O(n). 综上,复杂度为O(nlogn).