浙大数据结构01-复杂度1 最大子列和问题 (20 分)(方法总结)

题目:

输入样例:

6
-2 11 -4 13 -5 -2(结尾无空行)

输出样例:

20(结尾无空行)


主函数:

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

int MaxSubseqSum1(vector<int>List, int N);//算法1
int MaxSubseqSum2(vector<int>List, int N);//算法2
int MaxSubseqSum3(vector<int>List, int N);//算法3
int MaxSubseqSum4(vector<int>List, int N);//算法4

int main()
{
	int sum, x, i;
    vector<int>List;
    
    scanf("%d",&sum);
    for(i=0;i<sum;i++){
        scanf("%d",&x);
        List.push_back(x);
    }
	printf("%d ",MaxSubseqSum1(List,sum));  //算法1
	printf("%d ",MaxSubseqSum2(List,sum));  //算法2
	printf("%d ",MaxSubseqSum3(List,sum));  //算法3
	printf("%d ",MaxSubseqSum4(List,sum));  //算法4
	return 0;
}

 算法1:穷举所有最大子列和,从中找出最大值。算法复杂度是 O(N^3).

int MaxSubseqSum1(vector<int>List, int N)
{
	int ThisSum, MaxSum = 0;
	int i, j, k;
	for(i=0; i<N; i++){     //i是子列左端
		for(j=i; j<N; j++){     //j是子列右端
			ThisSum = 0;    //List[i]到List[j]的子列和
			for(k=i; k<=j; k++){
				ThisSum += List[k];//每次循环都是从头加数,只需要每次累加1项即可
			}
			if(ThisSum > MaxSum)
				MaxSum = ThisSum;//更新最大子列和
		}
	}
	return MaxSum;
}

算法2:对算法1的改进,降低了算法复杂度。算法复杂度是O(N^2);

int MaxSubseqSum2(vector<int>List, int N)
{
	int ThisSum, MaxSum = 0;
	int i, j;
	for(i=0; i<N; i++){  //i是子列左端
		ThisSum = 0;
		for(j=i; j<N; j++){  //j是子列右端
			ThisSum += List[j];//只需累加即可
			if(ThisSum > MaxSum)
				MaxSum = ThisSum;//更新子列和
		}
	}
	return MaxSum;
}

算法3:分而治之。

    如果把原始序列一分为二,那么最大子列和有以下三种情况:

             1.左半边;2.右半边;3.横跨中间的一段;

算法思想:

    1.将序列中分为左右两个序列;

    2.递归求出两个子列的最大和“S左”“S右”;

    3.从中分点向左,右两边扫描,找出横跨分界线的最大子列和“S中”;

    4.最大子列和为左右子列“S左”和“S右”与横跨的子列和“S中”的最大值;

int Max3(int A, int B, int C)
{
	return A>B ? (A>C ? A : C) : (B>C ? B : C); //返回A,B,C中的最大值;
}
int DivideAndConquer(vector<int>List, int left, int right)
{
	int MaxLeftSum, MaxRightSum;
	int MaxLeftBorderSum, MaxRightBorderSum;

	int LeftBorderSum, RightBorderSum;
	int center, i;

	if(left == right)//递归的终止条件
	{
		if(List[left] > 0)  return List[left];
		else                return 0;
	}
	//下面是“分”的过程
	center = (left + right)/2;//找中间点
	//递归求得两边子列的最大和
	MaxLeftSum = DivideAndConquer(List, left, center);
	MaxRightSum = DivideAndConquer(List, center + 1, right);

	//下面求得跨分界线的最大子列和
	MaxLeftBorderSum = 0; LeftBorderSum = 0;
	for(i=center; i>=left; i--){
		LeftBorderSum += List[i];
		if(LeftBorderSum > MaxLeftBorderSum)
			MaxLeftBorderSum = LeftBorderSum;
	}//左边扫描结束

	MaxRightBorderSum = 0; RightBorderSum = 0;
	for(i=center+1; i<=right; i++){
		RightBorderSum += List[i];
		if(RightBorderSum > MaxRightBorderSum)
			MaxRightBorderSum = RightBorderSum;
	}//右边扫面结束
	//下面返回“治”的结果;
	return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
}
int MaxSubseqSum3(vector<int>List, int N)
{
	return DivideAndConquer(List, 0, N-1);
}

算法4:在线处理。

//算法4:在线处理
int MaxSubseqSum4(vector<int>List, int N)
{
	int i;
	int ThisSum, MaxSum;

	ThisSum = MaxSum = 0;
	for(i=0; i<N; i++){
		ThisSum += List[i];  //向右累加
		if(ThisSum > MaxSum)
			MaxSum = ThisSum;  //发现更大和则更新当前结果;
		else if(ThisSum < 0)  //如果当前子列和为负;
			ThisSum = 0;  //则不可能使后面的部分和增大,抛弃之;
	}
	return MaxSum;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值