最大连续子序列和

1.O(n^2)

基本思路   对所有的情况进行遍历  ,  对其实地点i进行遍历 ,为N , 对终止地址j进行遍历 ,为N ,对i到j之间的内容进行累加求和  , 为N 所以能为O(n^3)的解法 ,但是在进行对i到j之间的累加的时候有 sum[i,j]=sum[i,j-1]+a[j]

所以可以压缩到O(n^2)

# include <stdio.h>
int n;
int a[500];
int main(){
    while(scanf("%d",&n)!=EOF){
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        int sumi=0,sumj=0;
        int maxsum = -9999999;
        for(int i=0;i<n;i++){
            int sum=0;
            for(int j=i;j<n;j++){
                sum+=a[j];
                if(sum>maxsum){
                    maxsum = sum;
                    sumi = i;
                    sumj = j;
                }
            }
        }
        printf("最大的连续子序列为 :  %d\n",maxsum);
        printf("起始位置为 %d   终止为止为  %d\n",sumi+1,sumj+1);
    }
    return 0;
}
2. dp方法  从后向前考虑一下  对于最后一个数  有三种情况  第一个是让他自己成为最大连续子序列  a[n-1]   第二种是 让以a[n-1] 结尾的序列成为最大连续子序列 记为end[n-1]  第三种是a[n-1] 根本就没有包括在最大连续子序列里面  所以就没有他的事  记为all[n-2]

所以在初始化过程中就可以记end[0] = all[0] = a[0]

然后从1开始遍历   得到一个O(n)的解决方案

# include <stdio.h>
int n;
int a[500];
int end[500];
int all[500];
int max(int a,int b){
    return a>b?a:b;
}
int main(){
    while(scanf("%d",&n)!=EOF){
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        all[0] = end[0] =a[0];
        for(int i=1;i<n;i++){
            end[i]=max(end[i-1]+a[i],a[i]);
            all[i]=max(all[i-1],end[i]);
        }
        printf("%d\n",all[n-1]);
    }
    return 0;
}

在这之中可以记录一下连续最大子序列的初始位置和最终的位置  

也可以有此推出另一种O(n)的方法  

# include<stdio.h>
int n;
int a[500];
int main(){
    while(scanf("%d",&n)!=EOF){
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        int sum = 0;
        int maxsum = -99999;
        int beginsum,endsum;
        for(int i=0;i<n;i++){

            if(sum>=0){
                sum+=a[i];
            }else{
                sum = a[i];
                beginsum = i;
            }
            if(sum>maxsum){
                maxsum = sum;
                endsum = i;
            }
        }
        printf("%d %d %d\n",maxsum,beginsum,endsum);
    }
    return 0;
}


3.  如果存在环的话

max(不允许存在环的情况下的最大连续子序列,所有序列的总和减去最小连续子序列的值(转换为对偶问题))

# include<stdio.h>
int n;
int a[500];
int maxsum_limited(){
    int sum =0;
    int maxsum = -999;
    for(int i=0;i<n;i++){
        if(sum<0){
            sum = a[i];
        }else {
            sum+=a[i];
        }
        if(sum>maxsum){
            maxsum = sum;
        }
    }
    return maxsum;
}
int maxsum_unlimited(){
    int total =0;
    int sum=0;
    int minsum =99999;
    int maxsum_li =  maxsum_limited();
    if(maxsum_li<0){
        return maxsum_li;
    }
    for(int i=0;i<n;i++){
        if(sum>0){
            sum = a[i];
        }else{
        sum+=a[i];
        }
        if(sum<minsum)
            minsum = sum;
        total += a[i];
    }
    return maxsum_li>(total-minsum)?maxsum_li:(total-minsum);
}
int main(){
    while(scanf("%d",&n)!=EOF){
        for(int i=0;i<n;i++){
            scanf("%d",&a[i]);
        }
        int sum = 0;
        int maxsum = -99999;
        printf("%d\n",maxsum_unlimited());
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值