题目地址:
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)。