原题地址:https://leetcode.com/problems/maximum-subarray/description/
题目:
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.
题解:
写这道题比较艰难。比较容易看出的解题思路就是通过判断当前累加的值决定最大子数组范围。比如,当前累加的值sum小于0时,就意味着可以把之前所有累加的值舍弃,并指向下一个元素。但我一直在思考如何同时确定两边的范围而不冲突,这就导致我陷入了一个死胡同,为此还花相当多的时间写了一个计算两边累加之和最小,然后再用总的和减去这个数的程序,但因为用到了嵌套循环,这个程序时间复杂度非常糟糕。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int size = nums.size(), count = 0, maxNum = 0, sum = 0;
for (int i = 0; i < size; i++) {
sum += nums[i];
if (nums[i] < 0) count++;
}
if (count == size) {
maxNum = nums[0];
for (int i = 1; i < size; i++)
if (nums[i] > maxNum) maxNum = nums[i];
return maxNum;
}
else if (count == 0) {
return sum;
}
map<int, int> sumls, sumrs;
sumls.insert(make_pair(-1, 0));
sumrs.insert(make_pair(size, 0));
vector<int> sums;
int suml = 0, sumr = 0;
for (int i = 0, j = size-1; i < size, j >= 0; i++, j--) {
suml += nums[i];
if (suml < 0) sumls.insert(make_pair(i, suml));
sumr += nums[j];
if (sumr < 0) sumrs.insert(make_pair(j, sumr));
}
int minNum = 0;
for (map<int, int>::iterator i = sumls.begin(); i != sumls.end(); i++) {
map<int, int>::iterator j;
if (sumrs.find(i->first + 1) == sumrs.end())
j = sumrs.begin();
else
j = sumrs.find(i->first + 1);
for (; j != sumrs.end(); j++) {
if (i->first < j->first&&i->second + j->second < minNum) minNum = i->second + j->second;
}
}
maxNum = sum - minNum;
return maxNum;
}
};
后来看了其他人的代码后发现,之前的思路是没有问题的,但是问题我无法确定另一侧的边界。因为在sum加上一个负数之后但是其值仍然大于0后,程序仍然会继续运行,但是这就不会是最大值,也无法确定之后是否sum会变得更大,因此我认为应该同时确定两个边界。事实上是我把问题想复杂化了,只需要使用一个变量,保存当前最大值,每次把新的sum和它做比较,再确定是否替换。这样就可以确保在所有区域中,能够选取和最大的一个。
新的代码如下:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int maxNumber = INT_MIN, sum = 0;
for (int i = 0; i < nums.size(); i++) {
if (sum > 0) {
sum += nums[i];
} else {
sum = nums[i];
}
maxNumber = max(sum, maxNumber);
}
return maxNumber;
}
};