目录
1.题目概述
给定一个包含 KK 个整数的序列 {N1,N2,…,NK}{N1,N2,…,NK}。
连续子序列定义为 {Ni,Ni+1,…,Nj}{Ni,Ni+1,…,Nj},其中 1≤i≤j≤K1≤i≤j≤K。
最大子序列是指序列内各元素之和最大的连续子序列。
例如,给定序列 {−2,11,−4,13,−5,−2}{−2,11,−4,13,−5,−2},它的最大子序列为 {11,−4,13}{11,−4,13},其各元素之和为 2020。
现在你需要求出最大子序列的各元素之和。
2.两种手工运算方法
(1)分治法比大小
对于含有n个整数的序列a[0...n-1],若n=1,表示该序列仅含一个元素,如果该元素大于0,则返回该元素。
若n>1,采用分治法求解最大连续子序列时,取其中间位置d=[(n-1)/2],该子序列只能出现在3个地方。
1.该子序列完全落在左半部分即a[0...mid]中。采用递归求出其最大连续子序列和maxLeftSum。
2.该子序列完全落在右半部即a[mid+1..n-1]中。采用递归求出其最大连续子序列和maxRightSum。
3. 该子序列跨越序列a的中部而占据左右两部分。
以上面的例题为例,利用分治法mid=(0+5)/2找到此时正中间的数组,以它为界将数组分为两个部分,一边是-2,11,-4,另外一边是13,-5,-2,还可以继续分治,mid=(0+2)/2=1,以它为界将其分为两个部分,然后继续进行分治,最后的结果就会与上面图片中相同。接下来我们求最大值,如果遇到子段之和小于0则将其置为0,求得每一个字段的最大值,最后进行比较(从下面往上求),每求得一行就要进行大小比较,最后求出最大值。
(2)边扫描边更新比大小
这是求解的另外一种方法,将数字从第一个开始扫描,然后进行累加,将累加结果放入thisSum中,而maxSum则需要进行判断,存入此时thisSum中出现的最大数,如果此时thisSum中的数字小于maxSum中,则不需要更新,如果此时的thisSum<0,则抛弃前面所有的累加数,从下一个数开始重新进行累加,直到所有的数字都被扫描结束。
-1 3 -2 4 -6 1 6 -1 thisSum = -1; maxSum =0;-1 3 -2 4 -6 1 6 -1 thisSum = 3; maxSum =3;-1 3 -2 4 -6 1 6 -1 thisSum = 1; maxSum =3;-1 3 -2 4 -6 1 6 -1 thisSum = 5; maxSum =5;-1 3 -2 4 -6 1 6 -1 thisSum = -1; maxSum =5;-1 3 -2 4 -6 1 6 -1 thisSum = 0; maxSum =5;-1 3 -2 4 -6 1 6 -1 thisSum = 1; maxSum =5;-1 3 -2 4 -6 1 6 -1 thisSum = 7; maxSum =7;-1 3 -2 4 -6 1 6 -1 thisSum = 6; maxSum =7;
3.代码实现
(1)Algorithm 1
时间复杂度:O(N^3)
int MaxSubSum1(const vector <int> & a) {
int maxSum=0;
for (int i=0; i<a.size(); i++) // i is the left end position of the subsequence
for (int j=i; j<a.size(); j++) {// j is the position of the right end of the subsequence
int thisSum=0; // thisSum is sum of subsequence from A [i] to A [j]
for (int k=i; k<=j; k++)
thisSum+=a[k];
if (thisSum>maxSum)//If you just get this subsequence and bigger maxSum=thisSum;//Update result
}
return maxSum;
}
(2)Algorithm 2
时间复杂度:O(N^2)
int MaxSubSum2(const vector <int> & a) {
int maxSum=0;
for (int i=0; i<a.size(); i++) {
thisSum=0;
for (int j=i; j<a.size(); j++) {
thisSum+=a[j];// For the same i and different j, just accumulate 1 term on the basis of j-1 cycles
if (thisSum>maxSum)
maxSum=thisSum;
}
}
return maxSum;
}
(3)Algorithm 3
时间复杂度:O(N)
int maxSumRec (const verctor<int> & a, int left, int right) {
if (left==right)
if (a[left]>0)
return a[left];
else
return 0;
int center = (left+right)/2;
int maxLeftSum=maxSumRec(a, left, center);
int maxRightSum=maxSumRec(a, center+1, right);
int maxLeftBorderSum=0, leftBorderSum=0;
for (int i=center; i>=left; i--) {
leftBorderSum += a[i];
if (leftBorderSum>maxLeftBorderSum)
maxLeftBorderSum=leftBorderSum;
}
int maxRightBorderSum=0; rightBorderSum=0;
for (int j=center+1; j<=right; j++) {
rightBorderSum+=a[j];
if (rightBorderSum>maxrightBorderSum)
maxRightBorderSum=rightBorderSum;
}
return max3(maxLeftSum, maxRightSum,
maxLeftBorderSum+maxRightBorderSum);
}
int maxSubSum3 (const vector <int> & a) {
return maxSumRec(a, 0, a.size()-1);
}
(4)Algorithm 4
时间复杂度:O(N)
int MaxSubSum4(const vector <int> & a) {
int maxSum=0, thisSum=0;
for (int j=0; j<a.size(); j++) {
thisSum+=a[j];//Accumulate right
if (thisSum>maxSum)//Find bigger and update current results maxSum=thisSum;
else if (thisSum<0)//If the current subsequence sum is negative thisSum=0;//Then it ’s impossible to increase the sum of the latter part and discard it. }
return maxSum;
}