最大子序列和问题的解_
2016-12-14 19:47
190 查看
问题:有数n1,n2,......,ns。求一个连续的子序列,这个序列的和最大。
这个问题有O(n^3)、O(n^2)、O(n*lgn)以及O(n)时间复杂度的解法。
下面主要说下O(n*lgn)和O(n)的解法。
1.O(n*lgn)是采用分治的思想。
前半部 后半部
4 -3 5 -2 -1 2 6 -2
最大子序列的和可能出现在三个地方:整体出现在前半部、整体出现在后半部、横跨中间部分而占据左右两部分。
前半部的最大子序列和为6(从A1到A3)而后半部分的最大子序列和为8(从A6到A7)。
前半部分包含其最后一个元素的最大和是4(从A1到A4),而后半部分包含第一个元素的最大和为7(从元素A5到A7)。横跨这两部分且通过中间的和最大为4+7=11。
所以三个数的最大值为11。
代码:
2.O(n)的方法。
设置一变量thisSum来记录前面所有项的累和。若thisSum小于0,则将其置为0,然后继续累加,在这过程中记录最大值。
代码:
int maxSubSum(const vector<int>& a)
{
int maxSum = 0, thisSum = 0;
for(int j = 0; j < a.size(); ++j)
{
thisSum += a[j];
if(thisSum>maxSum) maxSum = thisSum;
else if(thisSum<0) thisSum = 0;
}
return maxSum;
}优点:
1)时间复杂度低。
2)只用对数据进行一次扫描,一旦a[i]被读入并处理了,它就不需要被记忆。因此,如果数组在磁盘上,它就可被顺序读入,在主存中不必存储数组。在任意时刻,算法都能对已经读入的数据给出子序列问题的正确答案。这种特性的算法被称为联机算法。
这个问题有O(n^3)、O(n^2)、O(n*lgn)以及O(n)时间复杂度的解法。
下面主要说下O(n*lgn)和O(n)的解法。
1.O(n*lgn)是采用分治的思想。
前半部 后半部
4 -3 5 -2 -1 2 6 -2
最大子序列的和可能出现在三个地方:整体出现在前半部、整体出现在后半部、横跨中间部分而占据左右两部分。
前半部的最大子序列和为6(从A1到A3)而后半部分的最大子序列和为8(从A6到A7)。
前半部分包含其最后一个元素的最大和是4(从A1到A4),而后半部分包含第一个元素的最大和为7(从元素A5到A7)。横跨这两部分且通过中间的和最大为4+7=11。
所以三个数的最大值为11。
代码:
class Solution { public: int maxSubSum(const vector<int>& arr) { int m = divide_conquer(arr, 0, arr.size() - 1); return m; } int divide_conquer(const vector<int>& arr, int s, int e){ if (s == e) return arr[s]; else{ int m, lm, rm, lmm, rmm; int tmp = 0, mid = (s + e) / 2; lm = divide_conquer(arr, s, mid); lmm = arr[mid]; for (int i = mid; i >= s; --i){ tmp += arr[i]; if (tmp>lmm) lmm = tmp; } rm = divide_conquer(arr, mid + 1, e); rmm = arr[mid+1]; tmp = 0; for (int i = mid+1; i <= e; ++i){ tmp += arr[i]; if (tmp>rmm) rmm = tmp; } m = lm>rm ? lm : rm; if (m < (lmm + rmm)) m = lmm + rmm; return m; } } };
2.O(n)的方法。
设置一变量thisSum来记录前面所有项的累和。若thisSum小于0,则将其置为0,然后继续累加,在这过程中记录最大值。
代码:
int maxSubSum(const vector<int>& a)
{
int maxSum = 0, thisSum = 0;
for(int j = 0; j < a.size(); ++j)
{
thisSum += a[j];
if(thisSum>maxSum) maxSum = thisSum;
else if(thisSum<0) thisSum = 0;
}
return maxSum;
}优点:
1)时间复杂度低。
2)只用对数据进行一次扫描,一旦a[i]被读入并处理了,它就不需要被记忆。因此,如果数组在磁盘上,它就可被顺序读入,在主存中不必存储数组。在任意时刻,算法都能对已经读入的数据给出子序列问题的正确答案。这种特性的算法被称为联机算法。