[笔试面试高频题]
求一个数组的子数组中所有元素和的最大值。
子数组指一个或连续多个数组成的数组。
使用动态规划方法求解,算法的时间复杂度为O(n).
举个栗子:
输入数组为:6,-3,-2,7,-15,1,2,2
和最大的子数组为:6,-3,-2,7
输出该子数组的和为:8
解法:
用curSum[i]表示前i个元素(包含第i个, i从0开始)所组成的子数组的最大和,那么max(curSum)就是所有子数组的最大和。
curSum[i] = curSum[i-1] + array[i], if i == 0 || curSum[i-1] > 0
= array[i], if i > 0 || curSum[i-1] < 0
当前i-1个元素所组成的子数组的最大和为负数时,它与第i个元素之和一定比第i个元素小。此时,前i个元素所组成的子数组的最大和就是第i个元素的值。
当前i-1个元素所组成的子数组的最大和为正数时,它与第i个元素之和比第i个元素大。此时,前i个元素所组成的子数组的最大和为前i-1个元素所组成子数组的最大和加上第i个元素。
代码一:
class Solution {
public:
bool invalidArray = false;
int FindGreatestSumOfSubArray(vector<int> array) {
int n = array.size();
if (n < 1) {
invalidArray = true;
return 0;
}
vector<int> curSum(n,0);
curSum[0] = array[0];
for (auto i = 1; i<n; ++i) {
if (curSum[i-1] > 0) {
curSum[i] = array[i] + curSum[i-1];
} else {
curSum[i] = array[i];
}
}
int maxSum = curSum[0];
for (int i=1; i<n; ++i) {
maxSum = curSum[i]>maxSum ? curSum[i]: maxSum;
}
return maxSum;
}
}; // 时间复杂度O(n),空间复杂度O(n)
要找到所有子数组和中的最大和,每个元素至少需要遍历一边,因此算法的时间复杂度最少为O(n),已经是最优的了。
在上述代码中,我们用一个O(n)的额外空间curSum来存储前i个元素的子数组的最大和,但是程序最终只要一个最大值,因此可以考虑在计算curSum数组的过程中边计算边比较,即将第二个for循环放到第一个中执行,以此来节省空间复杂度。
代码二:
class Solution {
public:
bool invalidArray = false;
int FindGreatestSumOfSubArray(vector<int> array) {
int n = array.size();
if (n < 1) {
invalidArray = true;
return 0;
}
vector<int> curSum(n,0);
curSum[0] = array[0];
int maxSum = curSum[0];
for (auto i = 1; i<n; ++i) {
if (curSum[i-1] > 0) {
curSum[i] = array[i] + curSum[i-1];
} else {
curSum[i] = array[i];
}
maxSum = curSum[i] > maxSum ? curSum[i]: maxSum;
}
return maxSum;
}
}; // 时间复杂度O(n),空间复杂度O(1)
变量invalidArray用于在函数外检查输入的合法性。