您的位置:首页 > 其它

最大子序列和问题的解_

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。

    代码:

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]被读入并处理了,它就不需要被记忆。因此,如果数组在磁盘上,它就可被顺序读入,在主存中不必存储数组。在任意时刻,算法都能对已经读入的数据给出子序列问题的正确答案。这种特性的算法被称为联机算法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  分治