1007 Maximum Subsequence Sum

题目来源:PAT (Advanced Level) Practice

Given a sequence of K integers { N​1​​, N​2​​, ..., N​K​​ }. A continuous subsequence is defined to be { N​i​​, N​i+1​​, ..., N​j​​ } where 1≤i≤j≤K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.

Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.

Input Specification:

Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (≤10000). The second line contains K numbers, separated by a space.

Output Specification:

For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.

Sample Input:

10
-10 1 2 3 4 -5 -23 3 7 -21

Sample Output:

10 1 4

words:

continuous 连续的        element 元素       maximum 最大值的         indices(index的复数)索引

题意:

给定一个含n个元素的数列;若数列中的数全为负数则输出0、第一个元素和最后一个元素;否则找出一个和最大的连续子序列(若不唯一则选择靠近数列前面的),并输出最大和、子序列第一个元素和最后一个元素

思路:

1. 用数组a[]来存储题目给出的数列,与此同时并判断元素是否全为负数

2. 方法一:

        a. 使用dp[]数组来存放的以a[i]结尾的连续序列的最大和(dp[0]=a[0]);

        b. 使用s[]表示以a[i]作为结尾的最大连续子序列是从哪里开始 (下标)

        c. 然后从a[1]开始判断a[i]加上前面的序列和dp[i-1]能否使自己变大若变大则相加且连续序列增长,即dp[i]=dp[i-1]+a[i],s[i]=s[i-1];否则不相加且连续序列终止,即dp[i]=a[i],s[i]=i

        d. 最后找出最大的dp[i]输出,并输出序列第一个元素a[s[i]]和最后一个元素a[i]即可;

3. 方法二:

        a. 使用数组b[]存放a[]的 顺序累积和,即b[i]=a[0]+...a[i]

        b. 使用数组c[]存放a[]的 逆序累积和,即c[i]=a[i]+...a[n-1];(便于接下来快速求出区间序列的和);

        c. 使用双指针(i、j)通过双重循环求出区间 [i,j] 的和,记录最大和及对应的 i、j 指针值;  

        d. [i,j]区间和等于sum-b[i-1]-c[j+1](sum为整个数列的元素和);

        e. 输出最大和以及i、j指针对应的元素即可;

//PAT ad 1007 Maximum Subsequence Sum
#include <iostream>
using namespace std;
#include <iomanip>
/*
 -10    1    2    3    4   -5  -23    3    7  -21
 -10   -9   -7   -4    0   -5  -28  -25  -18  -39	b[] 
 -39  -29  -30  -32  -35  -39  -34  -11  -14  -21	c[]
 -10    1    3    6   10   5   -18    3   10  -11   dp[]数组 
*/
//-2 11 -4 13 -5 -2
void Method1()		//方法1 
{
	int n,m,i,j;
	cin>>n;
	int a[n];
	bool flag=false;	//标记是否有正数 
	for(i=0;i<n;i++)	//输入 
	{
		cin>>a[i];
		if(a[i]>=0)
			flag=true;
	}
	if(flag==false) 	//全为负数 
	{
		cout<<0<<" "<<a[0]<<" "<<a[n-1]<<endl; return ;
	}
	int dp[n];		//dp[i]存放的是以a[i]结尾的连续序列的最大和; 
	dp[0]=a[0];
	int s[n]={0};	//s[i]表示以a[i]作为结尾的最大连续子序列是从哪里开始 (下标) 
	for(i=1;i<n;i++)
	{
		if(a[i]+dp[i-1]>a[i])	//有更大的值,更新 (对于当前的a[i],加上更大则要加)
		{
			dp[i]=dp[i-1]+a[i];
			s[i]=s[i-1];
		}
		else				//从当前元素重新开始 
		{
			dp[i]=a[i];
			s[i]=i;
		}
	}
	int k=0;
	for(i=1;i<n;i++)	//找出最大值,即最大连续序列和 
	{
		if(dp[i]>dp[k])
			k=i;		//序列右区间 
	}
	cout<<dp[k]<<" "<<a[s[k]]<<" "<<a[k]<<endl;
}

void Method2()		//方法2 
{
	int n,m,i,j;
	cin>>n;
	int a[n];
	bool flag=false;	//标记是否有正数
	for(i=0;i<n;i++)	//输入 
	{
		cin>>a[i];
		if(a[i]>=0)
			flag=true;
	}
	if(flag==false) 		//全为负数 
	{
		cout<<0<<" "<<a[0]<<" "<<a[n-1]<<endl; return ;
	}
	
	int t=0;
	int ma=0;
	int b[n];
	int c[n];
	int sum=0;

	for(i=0;i<n;i++)	//顺序求累积和,即b[i]=a[0]+...a[i]; 
	{
		t+=a[i];
		b[i]=t;
		sum+=a[i];
	}
	
	for(i=n-1,t=0;i>=0;i--)	//逆序求累积和,即c[i]=a[i]+...a[n-1];
	{
		t+=a[i];
		c[i]=t;
	}
	t=a[0];	//区间和 
	int x,y;
	int index1=0,index2=0;
	for(i=0;i<n;i++)	//t表示区间[i,j]间的序列和; 
	{
		if(i==0)	x=0;
		else	x=b[i-1];
		for(j=i;j<n;j++)
		{
			if(j==n-1)	y=0;
			else	y=c[j+1];			
			if(t<sum-x-y)
			{
				t=sum-x-y;
				index1=i;	//标记最大序列和的起点 
				index2=j;	//...的终点 
			}	
		}	
	}
	cout<<t<<" "<<a[index1]<<" "<<a[index2]<<endl;
	
}
int main()
{
	//Method1();	//dp[]数组法 
	Method2();	//双指针法,双重循环解决问题 
		
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值