最大子序列和问题【分治法(附手工运算及多种源码)】

目录

1.题目概述

2.两种手工运算方法

(1)分治法比大小

(2)边扫描边更新比大小

 3.代码实现

(1)Algorithm 1

(2)Algorithm 2

(3)Algorithm 3

(4)Algorithm 4


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;
}

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值