题目:
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
.
click to show more practice.
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
首先想到的是用动态规划来做,因为动态规划跟前面计算的结果有关。
所以,对于给定的数组nums,我们可以定义一个相同大小的数组DP来存储当前元素对应的最大的连续元素之和。
以[−2,1,−3,4,−1,2,1,−5,4]举例分析。
当i=0时,DP[i]=-2;
当i=1时,DP[i]=1;
当i=2时,DP[i]=-2;
当i=3时,DP[i]=4;
......
很容易得出DP的递推式如下:
DP[i]=max(DP[i-1]+nums[i],nums[i]);
DP中最大值即为最后的返回值。
时间复杂度:O(n);
实现如下:
class Solution { public: int maxSubArray(vector<int>& nums) { int size = nums.size(); int maxSum = nums[0]; vector<int> DP(size, 0); DP[0] = nums[0]; for (int i = 1; i < size; i++) { DP[i] = max(DP[i - 1] + nums[i], nums[i]); if (DP[i]>maxSum) maxSum = DP[i]; } return maxSum; } };
分治策略是将数组分成两个规模尽可能相等的子数组,然后求解两个子数组。
但是最大子数组有可能出现在以下几种情况中:
完全位于子数组nums[low...mid]中;
完全位于子数组nums[mid...high]中;
跨越了中点;
因此我们需在上面三种情况中找最大者。
时间复杂度:O(nlgn)
实现如下:
class Solution { public: int maxSubArray(vector<int>& nums) { int size = nums.size(); if (size == 1) return nums[0]; return FindMaximumSubArray(nums,0,size-1); } private: int FindMaxCrossingSubArray(vector<int>& nums, int low, int mid, int high) { int leftSum = -0XFFFF, rightSum = -0XFFFF, tempSum = 0; for (int i = mid; i >= low; i--) { tempSum += nums[i]; if (tempSum > leftSum) leftSum = tempSum; } tempSum = 0; for (int i = mid + 1; i <= high; i++) { tempSum += nums[i]; if (tempSum > rightSum) rightSum = tempSum; } return leftSum + rightSum; } int FindMaximumSubArray(vector<int>& nums, int low, int high) { if (high == low) return nums[low]; int mid = (low + high) / 2; int leftSum = FindMaximumSubArray(nums,low,mid); int rightSum = FindMaximumSubArray(nums, mid+1, high); int crossSum = FindMaxCrossingSubArray(nums, low, mid, high); return max(max(leftSum, rightSum), crossSum); } };