最大连续和-高效算法

版权声明:未经博主同意,不可转载 https://blog.csdn.net/pythonbanana/article/details/87731643

求一个序列的最大连续区间和(有负数),可以前缀和,但是复杂度高。下面是复杂度为O(n)的高效算法。紫书P224,详情见代码注释。
后面还有分治递归的版本,复杂度O(n);

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<cstring>
#include<string>
#include<cmath>

using namespace std;

typedef long long LL;

#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i = a;i <= b;++i)
#define rep(i,a,b) for(int i = a;i >= b;--i)
const int maxn = 3e5;
int n = 0,m = 0;
int a[maxn+10];
int s[maxn+10];
int sm[maxn+10];//记录从1-j中最小的s的下标i,s[j] - s[i-1]最大,固定 s[j],相当于使s[i-1]最小
//然后扫描一次数组,维护目前遇到过的最小S
//复杂度O(n) ,紫书224页 

int main(){
	while(~scanf("%d",&n)){
		int l = 0,r = 0;//记录所求区间的端点值 
		memset(s,0,sizeof(s));
		 
		per(i,1,n){
			scanf("%d",&a[i]);
			s[i] = s[i-1] + a[i];
		}
		int mins = 0,min_id = 0;
		sm[1] = 0;
		per(i,2,n){//录从1-i中最小的sj的下标j ,s[j] - s[i-1]最大,固定 
			if(s[i-1] < mins){//取不取等号,要根据实际情况来 
				mins = s[i-1];
				sm[i] = min_id = i-1;
			}else{
				sm[i] = min_id;
			}
		}
		int maxv = -INF;
		per(i,1,n){
			if(s[i] - s[sm[i]] > maxv){
				l = sm[i] + 1;r = i;
				maxv = s[i] - s[sm[i]];
			}
		}
		
		printf("%d %d : %d\n",l,r,maxv);
	}
	
	
	return 0;
}

下面是归并的版本,复杂度O(nlogn):

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<cstring>
#include<string>
#include<cmath>

using namespace std;

typedef long long LL;

#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i = a;i <= b;++i)
#define rep(i,a,b) for(int i = a;i >= b;--i)
const int maxn = 3e5;
int n = 0,m = 0;
int a[maxn+10];
int max_sum(int *a,int x,int y){//返回数组左开右闭区间[x,y)中的最大连续和 
	if(y - x == 1){
		return a[x];//只有一个元素,直接返回 
	} 
	int mid = (y - x) / 2 + x;//分治第一步:划分成[x,mid),[mid,y) 
	int maxs = max(max_sum(a,x,mid),max_sum(a,mid,y));//分治第二步:递归求解 
	int maxv = 0;
	int l = a[mid-1];//不能初始化为0,因为输入有负数,下面max会出错 
	rep(i,mid-1,x){//分治第三步:合并(1)-从分界点开始往左的最大连续和 
		l = max(l,maxv += a[i]);
	}
	maxv = 0;
	int r =a[mid];
	per(i,mid,y-1){//分治第三步:合并(2)-从分界点开始往右的最大连续和 
		r = max(r,maxv += a[i]);
	}
	return max(maxs,l+r);//将子问题的解与l+r比较 
}
int main(){
	while(~scanf("%d",&n)){
		per(i,1,n){
			scanf("%d",&a[i]);
		}
		printf("%d\n",max_sum(a,1,n+1));
	}
	
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/pythonbanana/article/details/87731643
今日推荐