最大子序列和问题
【题目】
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.
【题解】
最大子序列和有多种解法,最简单的一种是遍历所有子序列,代码如下:
int maxSubArray(vector<int>& nums) {
int maxSum = INT_MIN;
for(int i = 0; i < nums.size(); i++) {
for(int j = i; j < nums.size(); j++) {
int nSum = 0;
for(int k=i; k<=j; k++)
nSum += nums[k];
if(nSum > maxSum)
maxSum = nSum;
}
}
return maxSum;
}
可看到代码中有三层循环嵌套,故其时间复杂度为O(n^3),同时,包含了很多重复的计算,效率很低,在LeetCode上提交会有Time Limit Exceeded的错误。
优化的办法很容易想到,我们只需遍历从起始位置开始的子序列就行了,代码如下:
int maxSubArray(vector<int>& nums) {
int nSize = nums.size();
if (nSize == 0)
return 0;
int maxSum = INT_MIN;
for(int i = 0; i < nSize; i++) {
int nSum = 0;
for(int j = i; j < nSize; j++) {
nSum += nums[j];
if(nSum > maxSum)
maxSum = nSum;
}
}
return maxSum;
}
其时间复杂度我们降到了O(n^2),虽然在LeetCode上提交可以得到Accept,但如果仔细观察的话会发现可以进一步改进。
假如起始位置的值为负,显然不是最大子序列和的起始点,一种特殊情况除外,即序列所有的值均为负数,这时我们只需要找到最大的负数即可。从负数不为最大子序列和的起点出发,我们可以得到下列代码:
int maxSubArray(vector<int>& nums) {
int nSize = nums.size();
if (nSize == 0)
return 0;
int maxSum = INT_MIN;
int nSum = 0;
for (int i = 0; i < nSize; i++) {
nSum += nums[i];
if (nSum > maxSum)
maxSum = nSum;
if (nSum < 0)
nSum = 0;
}
return maxSum;
}
时间复杂度为O(n)。