最大子段和
一、什么是最大子段和
在这里,要区别一下“子段”与“子序列”。子段是指连续的一部分,例如“23”是“12345”的子段,但“24”不是。
二、如何计算最大子段和
1.暴力搜索
枚举起点 i i i与终点 j j j,计算总和并保存结果。时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
2.动态规划(重点)
建造一个
d
p
dp
dp数组,其中,
d
p
[
i
]
dp[i]
dp[i]表示结尾是
i
i
i的最大子段和
那么,我们以
−
2
,
11
,
−
4
,
13
,
−
5
,
−
2
-2,11,-4,13,-5,-2
−2,11,−4,13,−5,−2为例,进行计算。
a[i] | dp[i] |
---|---|
-2 | |
11 | |
-4 | |
13 | |
-5 | |
-2 |
第一步,计算 d p [ 0 ] dp[0] dp[0], d p [ i ] dp[i] dp[i]有两种选择。第一种,是不选 a [ i ] a[i] a[i],那么 d p [ i ] = 0 dp[i]=0 dp[i]=0。第二种,是选 a [ i ] a[i] a[i],那么 d p [ i ] = a [ i ] dp[i]=a[i] dp[i]=a[i]。那么 d p [ 0 ] = m a x ( 0 , a [ 0 ] ) dp[0] = max(0,a[0]) dp[0]=max(0,a[0])。
a[i] | dp[i] |
---|---|
-2 | 0 |
11 | |
-4 | |
13 | |
-5 | |
-2 |
第二步,计算 d p [ 1 ] dp[1] dp[1]。跟上面一样,只不过不选的时候, d p [ i ] = a [ i ] + d p [ i − 1 ] dp[i] = a[i] + dp[i - 1] dp[i]=a[i]+dp[i−1]。那么 d p [ i ] = m a x ( 0 , a [ i − 1 ] ) dp[i] = max(0,a[i - 1]) dp[i]=max(0,a[i−1])
a[i] | dp[i] |
---|---|
-2 | 0 |
11 | 11 |
-4 | |
13 | |
-5 | |
-2 |
接着,以此类推。
a[i] | dp[i] |
---|---|
-2 | 0 |
11 | 11 |
-4 | 7 |
13 | 20 |
-5 | 15 |
-2 | 13 |
由于我们求的是最大子段和,所以还要求
d
p
dp
dp数组里的最大值。所以,最大子段和是一个1D/1D的模型。
但是还有一点要注意的是:全部都是负数的情况。例如:-2、-3、-20、-19、-5、-13。那么最大子段和就应该是所有数中的最大值。我们可以在输入的时候完成这个操作。
根据刚才的推断,我们得知了以下几个递推公式:
①
d
p
[
0
]
=
m
a
x
(
0
,
a
[
0
]
)
dp[0] = max(0,a[0])
dp[0]=max(0,a[0])
②
d
p
[
i
]
=
m
a
x
(
0
,
a
[
i
−
1
]
)
dp[i] = max(0,a[i - 1])
dp[i]=max(0,a[i−1])
那就上代码!
#include <iostream>
#include <algorithm>
using namespace std;
const int inf = 1e9;
int a[101], dp[101];
int main() {
int n;
cin >> n;
int ans = -inf;
for(int i = 1; i <= n; i++){
cin >> a[i];
ans = max(ans, a[i]);
}
dp[0] = max(0, a[0]);
for(int i = 1; i <= n; i++){
dp[i] = max(0, a[i - 1]);
ans = max(ans, dp[i]);
}
cout << ans << endl;
return 0;
}
这次就到这里了!记得点赞关注哦!