最大子列和问题

Maximum SubSequence Sum

Given a sequence of K integers { N1, N2, …, N**K }. A continuous subsequence is defined to be { N**i, N**i+1, …, N**j } where 1≤ijK. 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

题目大意

给定一段序列, 找到最大的连续子列, 并且算出它的和以及子列头的数字和子列尾的数字, 如果最大子列和为负数, 则将子列和置为0, 并且将子列头尾数字输出为整个序列的头尾数字.

算法分析

这个题目其实有很多种算法, 可以直接蛮力, 但是最好的复杂度也需要O(N^2), 实在是不尽人意; 分而治之也是一种解法, 但是不够简洁.

有一种算法可以达到常数级的复杂度. 即从序列左边开始一个个加, 定义一个thisSum代表当前最大的子列和, 初始化为0. 先将第一个数与当前最大子列和相加, 如果大于0, 说明这个数可以要, 并与总的最大子列和相比较, 如果大于总的最大子列和, 则更新最大子列和; 如果小于0, 说明这个数不能要, 这个数之前的序列也作废, 从当前数的下一个重新开始.

代码实现

#include<iostream>
using namespace std;

const int MAX = 10000;  //数据规模

int maxSubSeq(int a[], int n, int &head, int &tail)  //head代表序列头数字, tail代表序列尾数字
{
    int thisSum = 0, maxSum = -1;
    int temp = 0;
    for(int i=0; i<n; i++){  //仅一层循环遍历序列
        thisSum += a[i];  //计算出当前的子列和
        if(thisSum > maxSum){   //与最大的序列和比较,大于则更新最大序列和的值, 并且记录头尾数字下标
            maxSum = thisSum;
            head = temp;
            tail = i;
        }
        else if(thisSum < 0){ //如果当前序列和小于0, 则抛弃, 即重制当前序列和的值为0
            thisSum = 0;
            temp = i + 1;  //temp代表下次序列从哪里开始, 但是不会马上更新真正的head头部, 在找到序列和大于最大序列和后才会将temp的值赋给head, 以免后面都没有更大的子列了, 却更新了head头.
        }
    }
    return maxSum;
}


int main()
{
    int a[MAX], n;
    int head=0, tail=0;
    cin>>n;
    for(int i=0; i<n; i++){
        cin>>a[i];
    }
    int max = maxSubSeq(a,n,head,tail);
    if(max<0){
        cout<<0<<" "<<a[0]<<" "<<a[n-1];
    }
    else {
        cout<<max<<" "<<a[head]<<" "<<a[tail];
    }
    return 0;
}

总结

本题很容易想到蛮力的算法, 但是蛮力的算法一般都通过不了. 所以尽量优化, 蛮力不是一个好主意. 另外需要注意本题的数据集的范围, 以及头尾数字的下表控制, 还有在最大子列和为负数的时候, 要将最大子列和置为0, 并且输出的头尾数字是整个序列的头尾数字.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值