题目来源:PAT (Advanced Level) Practice
Given a sequence of K integers { N1, N2, ..., NK }. A continuous subsequence is defined to be { Ni, Ni+1, ..., Nj } 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;
}