题目地址:
https://www.acwing.com/problem/content/1060/
给定一个长度为 N N N的数组,数组中的第 i i i个数字表示一个给定股票在第 i i i天的价格。设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。卖出股票后,你无法在第二天买入股票(即冷冻期为 1 1 1天)。
输入格式:
第一行包含整数
N
N
N,表示数组长度。第二行包含
N
N
N个不超过
10000
10000
10000的正整数,表示完整的数组。
输出格式:
输出一个整数,表示最大利润。
数据范围:
1
≤
N
≤
1
0
5
1≤N≤10^5
1≤N≤105
思路是动态规划,可以用状态机来模拟整个过程,设三个状态,分别是持有、卖出和冷冻。设
f
[
i
]
[
0
,
1
,
2
]
f[i][0,1,2]
f[i][0,1,2]分别代表第
i
i
i天结束时的三个状态下的最大利润,并且设第
i
i
i天股价是
p
[
i
]
p[i]
p[i],则有:
1、今天持有可以由昨天持有、昨天冷冻转移而来,则有
f
[
i
]
[
0
]
=
max
{
f
[
i
−
1
]
[
0
]
,
f
[
i
−
1
]
[
2
]
−
p
[
i
]
}
f[i][0]=\max\{f[i-1][0],f[i-1][2]-p[i]\}
f[i][0]=max{f[i−1][0],f[i−1][2]−p[i]};
2、今天卖出可以由昨天持有转移而来,所以
f
[
i
]
[
1
]
=
f
[
i
−
1
]
[
0
]
+
p
[
i
]
f[i][1]=f[i-1][0]+p[i]
f[i][1]=f[i−1][0]+p[i];
3、今天冷冻可以由昨天冷冻或者昨天卖出转移而来,所以
f
[
i
]
[
2
]
=
max
{
f
[
i
−
1
]
[
2
]
,
f
[
i
−
1
]
[
1
]
}
f[i][2]=\max\{f[i-1][2],f[i-1][1]\}
f[i][2]=max{f[i−1][2],f[i−1][1]}。
最后返回
max
{
f
[
n
]
[
1
]
,
f
[
n
]
[
2
]
}
\max\{f[n][1],f[n][2]\}
max{f[n][1],f[n][2]}。代码如下:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n;
int a[N], hold[N], sell[N], cool[N];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
hold[0] = sell[0] = -1e9;
for (int i = 1; i <= n; i++) {
hold[i] = max(hold[i - 1], cool[i - 1] - a[i]);
sell[i] = hold[i - 1] + a[i];
cool[i] = max(cool[i - 1], sell[i - 1]);
}
cout << max(sell[n], cool[n]) << endl;
return 0;
}
时空复杂度 O ( N ) O(N) O(N)。