给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [2,4,1], k = 2
输出: 2
解释: 在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。
示例 2:
输入: [3,2,6,5,0,3], k = 2
输出: 7
解释: 在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。
随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:本题需要用到的一些点和前面122. 买卖股票的最佳时机 II以及123. 买卖股票的最佳时机 III有一些共性的地方。
假设N
为price
数组的大小。
那么首先第一个trick
的地方在于,如果k > N/2
,那么我们可以直接转化为122. 买卖股票的最佳时机 II,为什么呢?
因为我们即便全都是今天买,明天卖,那么最多可以买卖的次数为N / 2
的下整次,这里可以自己举个栗子说明,即k
如果大于N/2
,那么多出来的那些次数完全是今天买今天卖的无用功。所以也可以等效为买卖无限多次了。即退化为122. 买卖股票的最佳时机 II。
再来看k<=N/2
的情况:
参考123. 买卖股票的最佳时机 III的分析情况,我们可以得到买卖过程中会出现的阶段有如下情况:
即我们的阶段从5
增长到了2k+1
次,所以我们把123
题中的5
改为2k+1
就行了。
分析的过程是一样的。
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
if(n == 0)
return 0;
if(k > n/2)
{
//这里就退化成了可以买卖任意多次
int sum = 0;
for(int i = 0;i < n-1;++i)
{
if(prices[i+1] > prices[i])//只要后面一天的价格大于前一天的价格
sum += prices[i + 1] - prices[i];
}
return sum;
}
vector<vector<int>>f(n+1,vector<int>(2*k+2,0));
//初始化 f[i][j]表示在前i天中处于阶段j的最大获利
f[0][1] = 0;
for(int j = 2;j <= 2*k+1;++j)
{
f[0][j] = INT_MIN;
}
for(int i = 1;i<=n;++i)
{
//阶段1,3,5...2*k+1
for(int j = 1;j<=2*k+1;j+=2)
{
//f[i][j] = f[i-1][j];
if(j > 1&& i>=2)
{
f[i][j] = max(f[i-1][j],f[i-1][j-1] + prices[i-1] - prices[i-2]);
}
}
//阶段2,4...2k
for(int j = 2;j<=2*k+1;j+=2)
{
//f[i][j] = f[i-1][j-1];
if(i>=2)
{
f[i][j] = max(f[i-1][j-1],f[i-1][j]+prices[i-1]-prices[i-2]);
}
}
}
return *max_element(f[n].begin(),f[n].end());//最大值肯定是第n天来表示