概念
给定一个由数字组成的序列,其中连续的一段子序列称为一个 子段,子段中的所有数之和称为 子段和,这里只考虑非空子段,即至少包含一个元素的子段。我们来学习如何求得一个序列中子段和最大的子段的子段和,即求 最大子段和。
暴力算法
最暴力的算法,就是枚举两个端点,再遍历所选出的子段求和。整体时间复杂度为 O(n3)。
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
int sum = 0;
for (int k = i; k <= j; k++) {
sum += a[k];
}
ans = max(ans, sum);
}
}
优化一下,在固定左端点的情况下移动右端点,把新看到的一位加进来,时间复杂度 O(n2)
for (int i = 1; i <= n; i++) {
int sum = 0;
for (int j = i; j <= n; j++) {
sum += a[j];
ans = max(ans, sum);
}
}
动态规划算法
最后答案就是 dp 数组中的最大值。
for (int i = 1; i <= n; i++) {
if (dp[i - 1] >= 0) {
dp[i] = dp[i - 1] + a[i];
} else {
dp[i] = a[i];
}
}
for (int i = 1; i <= n; i++) {
ans = max(ans, dp[i]);
}
完整代码
#include <iostream>
#include <algorithm>
using namespace std;
const int inf = 1000000000;
int a[105], dp[105];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for(int i = 1; i <= n; i++){
if (dp[i - 1] >= 0){
dp[i] = dp[i - 1] + a[i];
}else {
dp[i] = a[i];
}
}
int ans = -inf;
for(int i = 1; i <= n; i++){
ans = max(ans, dp[i]);
}
cout << ans;
return 0;
}