最大连续子序列和
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 }
老实为人,踏实为学