最大连续子序列和问题如下:
下面介绍动态规划的做法,复杂度为 O(n)。
步骤 1:令状态 dp[i] 表示以 A[i] 作为末尾的连续序列的最大和(这里是说 A[i] 必须作为连续序列的末尾)。
步骤 2:做如下考虑:因为 dp[i] 要求是必须以 A[i] 结尾的连续序列,那么只有两种情况:
-
- 这个最大和的连续序列只有一个元素,即以 A[i] 开始,以 A[i] 结尾。
- 这个最大和的连续序列有多个元素,即从前面某处 A[p] 开始 (p<i),一直到 A[i] 结尾。
对第一种情况,最大和就是 A[i] 本身。
对第二种情况,最大和是 dp[i-1]+A[i]。
于是得到状态转移方程:
dp[i] = max{A[i], dp[i-1]+A[i]}
这个式子只和 i 与 i 之前的元素有关,且边界为 dp[0] = A[0],由此从小到大枚举 i,即可得到整个 dp 数组。接着输出 dp[0],dp[1],...,dp[n-1] 中的最大子即为最大连续子序列的和。
代码如下:
// threadtest.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
using namespace std;
//最大子序列之和
//给定一个数字序列A1,A2,...An,求i,j(1<=i<=j<=n),使得Ai+...+Aj最大,输出这个最大和。
//样例:
//-2 11 -4 13 -5 -2
//显然11+(-4)+13=20为和最大的选取情况,因此最大和为20
#define maxn 10010
int dp[maxn];//dp[i]存放以A[i]为结尾的连续序列的最大和
// 求较大值
int max(int a, int b) {
return a > b ? a : b;
}
int getMaxSubSum(const vector<int>& vecNum)
{
dp[0] = vecNum.at(0);
for (size_t i = 1; i < vecNum.size(); i++)
{
//状态转移方程
dp[i] = max(vecNum.at(i), dp[i - 1] + vecNum.at(i));
}
//求最大连续子序列和
int k = dp[0];
for (int i = 1; i< vecNum.size(); i++)
{
if (dp[i] > k)
k = dp[i];
}
return k;
}
int main()
{
vector<int> vecNum = { -2,11,-4,13,-5,2 };
int maxSubSum = getMaxSubSum(vecNum);
cout << "the maxsubsum=" << maxSubSum << endl;
system("pause");
return 0;
}