LintCode 1691. 买卖股票的最佳时机V
题目描述
给出一个股票n天的价格,每天最多只能进行一次交易,可以选择买入一支股票或卖出一支股票或放弃交易,输出能够达到的最大利润值
样例
样例 1:
给出 a = [1,2,10,9]
, 返回 16
输入:
[1,2,10,9]
输出:
16
解释:
你可以在第一天和第二天买入股票,第三天和第四天卖出
利润:-1-2+10+9 = 16
样例 2:
给出 a = [9,5,9,10,5]
, 返回 5
输入:
[9,5,9,10,5]
输出:
5
解释:
你可以在第2天买入,第4天卖出
利润:-5 + 10 = 5
注意事项
1 ≤ n ≤ 10000
解题思路
这道股票买卖问题,与以往的限制一次买卖、限制两次买卖、限制k次买卖、限制卖出后才能下一次买入……都不同,并不限制持有的股票数量,可以随时买入卖出。
这里直接使用状态转移方程,每一天有3个状态:买入、卖出、无操作。
使用dp[i][j]表示第i天持有j只股票的最大收益,则 dp[i][j] = max(dp[i-1][j-1]-a[j-1], dp[i-1][j+1]+a[j-1], dp[i-1][j])
。
参考代码
class Solution {
public:
/**
* @param a: the array a
* @return: return the maximum profit
*/
int getAns(vector<int> &a) {
// write your code here
if (a.size() <= 1) return 0;
size_t n = a.size();
vector<vector<int>> dp(n+1, vector<int>(n+1)); // 前 i 天进行 j 次买卖的最大利润
for (int i=0; i<n; i++) {
dp[i][0] = 0;
dp[0][i] = 0;
}
for (int i=1; i<=n; i++) {
dp[i][0] = std::max(dp[i-1][0], dp[i-1][1]+a[i-1]);
dp[i][i] = dp[i-1][i-1] - a[i-1];
dp[i][i-1] = std::max(dp[i-1][i-1], dp[i-1][i-2] - a[i-1]);
for (int j=1; j<=i-2; j++) {
dp[i][j] = max3(
dp[i-1][j], // 不操作
dp[i-1][j-1]-a[i-1],// 买入
dp[i-1][j+1]+a[i-1] // 卖出
);
}
}
int res = 0;
for (int j=0; j<n; j++) {
res = std::max(res, dp[n][j]);
}
return res;
}
static inline int max3(int a, int b, int c) {
int m = a > b ? a : b;
return m > c ? m : c;
}
};
minor fix:
- if(i>=2) dp[i][i-1] = std::max(dp[i-1][i-1], dp[i-1][i-2] - a[i-1]);
- 不从dp[n]中选最大值,直接return dp[n][0];