最大子序列和 O(n)算法

  • 最大子序列和:

给定一个包含 K 个整数的序列 {N1,N2,…,NK}

连续子序列定义为 {Ni,Ni+1,…,Nj}
,其中 1≤i≤j≤K

最大子序列是指序列内各元素之和最大的连续子序列。

例如,给定序列 {−2,11,−4,13,−5,−2},它的最大子序列为 {11,−4,13},其各元素之和为 20

现在你需要求出最大子序列的各元素之和,并且输出最大子序列的第一个元素和最后一个元素的值。
输入格式

第一行包含一个整数 K
第二行包含 K个整数。
输出格式

输出一行三个整数,分别表示最大子序列的各元素之和以及最大子序列的第一个元素和最后一个元素的值。

设最大子序列为 {Ni,Ni+1,…,Nj}
,如果答案不唯一,则选择 i 更小的解,如果仍不唯一,则选择 j

更小的解。

注意,我们规定,如果所有 K个数字均为负数,则其最大和定义为 0,并且应该输出整个序列的第一个数字和最后一个数字。

数据范围
1≤K≤10000
序列内元素的绝对值不超过 10^5

输入样例:

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

输出样例:

10 1 4
思路1:前缀和+遍历
时间复杂度 O(n^2)

#include<iostream>
using namespace std;
const int N=100010;
int a[N],b[N];
int main(){
    int n,m;
    cin>>n;int max=-1;//避免出现最大子列和恰好为0,导致输出错误
    int p,q;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        b[i]=b[i-1]+a[i];
    }
for(int i=0;i<n;i++){
    for(int j=i+1;j<=n;j++){
        if((b[j]-b[i])>max){
        max=b[j]-b[i];
        p=i+1;//注意边界问题
        q=j;
         }
    }
}if(max>=0)cout<<max<<' '<<b[p]-b[p-1]<<" "<<b[q]-b[q-1]<<endl;
else cout<<0<<" "<<a[1]<<" "<<a[n]<<endl;
}

思路2:
时间复杂度 :O(n)

#include<iostream>
using namespace std;
const int N=10010;
int a[N],b[N];
int n,m;
int main(){
    cin>>n>>m;int thismax=0,max=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        thismax+=a[i];
        if(thismax>max){
            m=a[i];
            max=thismax;
            
        }
       else if(thismax<0)thismax=0;//当前子序列和为负,则不可能使后面和增大,抛弃
         }cout<<max<<" "<<m;
         for(;max!=0;m--){//已知最大子序列和的终止元素,倒推起始元素
             max-=a[m];
         }
         cout<<a[m+1]<<endl;
}

思路3:
时间复杂度:O(n)

#include<iostream>
using namespace std;
const int N=10010;
int a[N];
int n,m,p;
int main(){
    cin>>n;int thismax=0,
    max=-1,
    j=0,//记录序列小于0元素个数
    len=0;//记录最大子序列和的元素个数
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        thismax+=a[i];
        len++; if(thismax>max){
        m=a[i];
        p=a[i-len+1];
        max=thismax;}
        if(thismax<0){thismax=0;len=0;}//当前子序列和为负,则不可能使后面和增大,抛弃
        if(a[i]<0)j++; 
        
    }
         if(j==n)cout<<0<<' '<<a[1]<<' '<<a[n]<<endl;
         else { cout<<max<<' '<<p<<' '<<m<<endl;}}

搞到半夜才把复杂度降到O(n),太难了。。。。。在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值