连续子列最大和问题

今天,在做PAT的一道题时遇到了一道题,其要解决的问题是如何在一个序列中,找出其拥有最大和的连续子列,例如:

{2,11,4,13,5,2}
得出:
{11,4,13}

首先会想到的一种方法,很暴力很慢,那就是用两个循环将子序列的首尾确定然后在用一个循环进行 ,于是就写出了如下代码:

#include <iostream>
#include <limits.h>
using namespace std;
int k;
int main ()
{
    int maxSum = INT_MIN, start = 0, end = 0;
    int arr[10000];
    cin>>k;
    for (int i = 0; i < k; i++)
        cin>>arr[i];
    for (int i = 0; i < k; i++) {
        for (int j = i; j < k; j++) {
            int sum = 0, x = i;
            for (; x <= j; x++)
                sum += arr[x];
            if (maxSum < sum) {
                maxSum = sum;
                start = arr[i];
                end = arr[x - 1];
            }
        }
    }
    cout<<maxSum<<" "<<start<<" "<<end<<"\n";
    return 0;
}

这个算法复杂度显而易见为 O(n3) ,这种复杂度实现是太高,我们需要来改进下,我们不如将 的过程给提前保存在下,也就是在cin时,就顺便生成一个存储前面i位和的数组,这样就可以将复杂度降到 O(n2)

#include <iostream>
#include <limits.h>
using namespace std;
int k;
int main ()
{
    int maxSum = INT_MIN, start = 0, end = 0;
    int arr[10000];
    int sum[10000];
    cin>>k;
    sum[0] = 0;
    for (int i = 0; i < k; i++) {
        cin>>arr[i];
        sum[i + 1] = sum[i] + arr[i];
    }
    for (int i = 1; i <= k; i++) {
        for (int j = i; j <= k; j++) {
            int temp = sum[j] - sum[i - 1];
            if (temp > maxSum) {
                maxSum = temp;
                start = arr[i - 1];
                end = arr[j - 1];
            }
        }
    }
    cout<<maxSum<<" "<<start<<" "<<end<<"\n";
    return 0;
}

这样做的话就讲我们的复杂度降下了一个次幂(ps: 没想到PAT测试通过了,并没有运行超时),那么还有没有机会将复杂度降到线性的 O(n) 呢?这个肯不可以用动态规划来做呢?首先我们来考虑一下状态转移的函数,很容易得出:

sum[i]=max{sum[i1]+a[i],a[i]}

sum[i] 代表的就是以 a[i] 做为结尾时的最大和,代码也是很容易写出来:

#include <iostream>
#include <limits.h>
using namespace std;
int k;
int main ()
{
    int maxSum = -0xfffffff, start = 0, end = 0, sum =  -0xfffffff, s = 0;
    int arr[10000];
    cin>>k;
    arr[0] = 0;
    for (int i = 1; i <= k; i++) {
        cin>>arr[i];
        if (sum + arr[i] < arr[i]) {
            sum = arr[i];
            s = i;
        } else
            sum += arr[i];
        if (sum > maxSum) {
            maxSum = sum;
            end = arr[i];
            start = arr[s];
        }
    }
    cout<<maxSum<<" "<<start<<" "<<end<<"\n";
    return 0;
}

这个问题同样可以被引申为买卖股票的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值