最大连续子序列和

1. 问题描述

 

给定一个序列 A[ 1 : n ],求其一个子序列 A[ i : j ],使得从 A[ i ] 到 A[ j ] 的和最大。

 

2. 动态规划解

用 opt[ i ] 表示以 A[ i ] 为末尾元素的所有连续子序列和的最大者,则

  • opt[ 1 ] = A[ 1 ]

当 i > 1 时:

  • 如果 opt[ i - 1 ] <= 0, 则 opt[ i ] = A[ i ]
  • 如果 opt[ i - 1 ] > 0, 则 opt[ i ] = A[ i ] + opt[ i - 1 ]

则结果为 max{ opt[1], opt[2], ..., opt[n] }。

 

时间复杂度为 O(n), 空间复杂度为 O(1)。

 

3. 扩展:首尾相连的情形

考虑序列 B = [A1, A2, ..., An, A1, A2, ..., An], 既两个 A 首尾相连。则要求的连续子序列要么在一个 A 中, 要么跨越两段 A, 对于后一种情况,遍历一下即可, 不过时间复杂度变为 O(n^ 2)

 

c++代码如下:

#include<iostream>
#include<vector>
#include<iterator>
#include<algorithm>

template<class Iter>
typename std::iterator_traits<Iter>::value_type max_sub_sum(Iter beg, Iter end)
{
    if(beg == end) return 0;
    typedef typename std::iterator_traits<Iter>::value_type value_type;

    value_type opt_i = *beg++;  //opt[i - 1]
    value_type opt = opt_i;

    for(; beg != end; ++beg)
    {
        opt_i = (opt_i > 0) ? (opt_i + *beg) : *beg;
        if(opt_i > opt)
            opt = opt_i;
    }
    return opt;
}

template<class Iter>
typename std::iterator_traits<Iter>::value_type max_sub_sum_loop(Iter beg, Iter end)
{
    if(beg == end) return 0;
    typedef typename std::iterator_traits<Iter>::value_type value_type;
    value_type opt = max_sub_sum(beg, end);

    int n = end - beg;
    std::vector<value_type> a1(n), a2(n);
    std::partial_sum(std::reverse_iterator<Iter>(end), std::reverse_iterator<Iter>(beg), a1.begin());
    std::partial_sum(beg, end, a2.begin());

    // O(n^2)
    for(int i = 0; i < n - 1; ++i)   // i + 1为从前半段取的元素数目
        for(int j = 0; j < n - i - 1; ++j) // j + 1为从后半段取的元素数目
        {
            auto tmp = a1[i] + a2[j];
            if(tmp > opt)
                opt = tmp;
        }
    return opt;
}


    
int main()
{
    int a[] = {0, -2, 3, 5, -1, 2};
    std::cout << max_sub_sum(a + 0, a + sizeof(a)/sizeof(int)) << std::endl; //9

    std::vector<double> b = {-1.1, -3.4, -2, -5};
    std::cout << max_sub_sum(b.begin(), b.end()) << std::endl; //-1.1

    int c[] = {1, 2, -4, 5, 6}; 
    std::cout << max_sub_sum_loop(c + 0, c + sizeof(c) / sizeof(int)) << std::endl; //14
}

 

 

posted @ 2013-09-21 20:58  半亩梨花  阅读(148)  评论(0编辑  收藏  举报