题目描述:输入一个整型的数组,数组里有可能有正数也可能有负数。数组中连续的一个或多个整数组成该数组的一个子数组,
每个子数组的所有元素的和称为子数组的和。求该数组的所有子数组的和的最大值。
分析:如果数据不多,可以用简单的方式遍历所有可能的子数组的和,求出最大的即可。用两层循环可以给出一个O(n^2)的算法,如下所示:
/*
* @func: max_sub_sum_n2
* @desc: Given a array of integer,
* return the max of its all sub array sums
* in an O(n^2) time complexity
* @param:
* v: input integer array
*
* @retval: max sub sum
*/
int max_sub_sum_n2(const std::vector<int>& v)
throw (std::out_of_range)
{
if (v.empty()) throw std::out_of_range("Array is empty!");
typedef std::vector<int>::size_type vsize_t;
vsize_t end_pos = v.size();
vsize_t start_pos = 0;
int max = v[start_pos];
for (; start_pos != end_pos; start_pos++) {
int sum = 0;
for (vsize_t iter = start_pos; iter != end_pos; iter++) {
sum += v[iter];
if (max < sum) max = sum;
}
}
return max;
}
该算法是一个O(n^2)的算法,我们可以用它来做一个结果的对比验证方式。 下面进一步考虑O(n)的算法。
首先我们考虑一个例子。假设输入的数组为4, -3, -2, 7, -1, 2, 4。 该数组的和最大的子数组为7, -1, 2, 4。
让我们按照上面的算法执行一遍来看一下:
首先,i = 0, 此时计算所有从A0开始的子数组的和
1, j = 0; 所以 sum = 4, max = 4; 这时候子数组为 A0
2, j = 1;此时,sum = 4 + (-3) = 1, max = 4; 这时候子数组为 A0, A1
3, j = 2;此时,sum = 1 + (-2) = -1, max = 4; 这时候子数组为A0, A1, A2
此时,sum = -1 已经小于0了。 在i = 0的剩下的循环中, 所有以A0开始的子数组的和都不会超过相应的从A3开始的子数组的和。因此,再将j继续循环下去是没有意义的。
故可以直接将i推进到 i + 1而无须继续进行剩余的循环。
当推进 i 的时候,我们进一步考虑。由于在上面的循环中,在j = 2之前,所有以A0...Aj 子数组的和均为正数,A0 ... A2是第一个和为负的数组。故,任何以Ak (k = 1 .. 2)开头的
数组都不会比加上A0 ... Ak-1 的子数组的和大。考虑到这一点,我们可以将i继续从i + 1推进到j + 1.
因此,当第一层循环的和为负值了之后,我们可以直接将i推进到为负值的下一个位置,继续循环,直到循环完成整个数组。这样,两层循环变为 1层循环,复杂度也降低为O(n)。代码如下:
/*
* @func: max_sub_sum_n2
* @desc: Given a array of integer,
* return the max of its all sub array sums
* in an O(n) time complexity
* @param:
* v: input integer array
*
* @retval: max sub sum
*/
int max_sub_sum_n(const std::vector<int>& v)
throw (std::out_of_range)
{
if (v.empty())
throw std::out_of_range("Array is empty");
typedef std::vector<int>::size_type vsize_t;
vsize_t end_pos = v.size();
vsize_t start_pos = 0;
int max = v[start_pos];
int sum = 0;
for (vsize_t iter = start_pos; iter != end_pos; iter++) {
sum += v[iter];
if (max < sum) max = sum;
if (sum <= 0) sum = 0;
}
return max;
}
注意,这里面其实没有必要考虑过多0的问题。只要将max的初始化为数组第一个元素的值即可处理全为负数的情况。