7-2 最大子段和 (40 分)

题目:

给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时,定义子段和为0。

要求算法的时间复杂度为O(n)。

输入格式:

输入有两行:

第一行是n值(1<=n<=10000);

第二行是n个整数。

输出格式:

输出最大子段和。

输入样例:

在这里给出一组输入。例如:

6
-2 11 -4 13 -5 -2

输出样例:

在这里给出相应的输出。例如:

20

算法描述:

采用一维填表法 。

难点:不知道什么时候结束
设:
a[] :存数
s[i]: 以a[i]为结尾的最大字段和
则可以得到数组元素之间的关系:
if s[i-1]<=0 s[i]=a[i]
if s[i-1]>0 a[i]+s[i-1]

代码:

#include <bits/stdc++.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	int a[n];
	int s[n]={0};// s[i]:以第i个数结尾的最大子段和
	int flag=0;// 记录负数的个数的 
	for(int i=0;i<n;i++){
		cin>>a[i];
		if(a[i]<0) flag++;
	}
	 
	if(flag==n) cout<<0;//当所给的整数均为负数时,定义子段和为0。
	else{
		s[0]=a[0];
		for(int i=1;i<n;i++){
			if(s[i-1]<=0) s[i]=a[i];
			else s[i]=s[i-1]+a[i];
		}
	int max=s[0];
	for(int i=0;i<n;i++){
		if(max<s[i]) max=s[i];
		
	}
	cout<<max;	
			
	}
	
	
}

在这里插入图片描述

进一步引申思考:
如何找到最大子序列是哪几个构成的?
不难发现,我们只要把递推关系式逆过来就行了。

#include <bits/stdc++.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	int a[n];
	int s[n]={0};// s[i]:以第i个数结尾的最大子段和
	int flag=0;// 记录负数的个数的 
	for(int i=0;i<n;i++){
		cin>>a[i];
		if(a[i]<0) flag++;
	}
	 
	if(flag==n) cout<<0;//当所给的整数均为负数时,定义子段和为0。
	else{
		s[0]=a[0];
		for(int i=1;i<n;i++){
			if(s[i-1]<=0) s[i]=a[i];
			else s[i]=s[i-1]+a[i];
		}
	int max=s[0],index=-1;
	for(int i=0;i<n;i++){
		if(max<s[i]){
			max=s[i];
			index=i;
		} 
		
	}
	cout<<max<<endl;

	// 改一改题:
	//并要输出最大子段和所对应的子段
	stack<int> child;
	for(int i=index;i>=0;i--){
		if(s[i-1]<=0){
			child.push(a[i]);
			break;
		}
		else child.push(s[i]-s[i-1]);
	} 
	cout<<"下面输出最大子段和所对应的子段序列:"<<endl; 
	while(!child.empty()){
		cout<<child.top()<<" ";
		child.pop();
	}
}}

改进后的运行结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值