【dp】leetcode Best Time to Buy and Sell Stock IV

时间:2022-03-15 15:00:32

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/description/

【题意】

给定n天股市的票价,最多交易k次,问最大盈利是多少,手上不能同时持有两支股票。

【思路】

考虑加入当天买当天卖这种情况,问题转换为n天总共交易k次(不是最多),因为后一次的买一定在前一次卖之后,所以需要dp[i][j]表示前i天交易j次且最后一次交易在第i天的最大利润。则

dp[i][j]=max(a[i]-a[k]+global[k-1][j-1]) 1<=k<=i

k=i表示当天买当天卖,global[i][j]表示max{dp[k][j]} 1<=k<=i

注意这里是global[k-1][j-1]而不是global[k][j],因为若最后一次交易恰好在第k天,则a[i]-a[k]+global[k][j-1]一共进行j-1次交易,而不是j次。

dp[i][j]=max(a[i]-a[k]+global[k-1][j-1])(1<=k<=i)

=max(a[i]-a[i-1]+a[i-1]-a[k]+global[k-1][j-1],global[i-1][j-1])) (1<=k<=i-1)

=max(a[i]-a[i-1]+dp[i-1][j],global[i-1][j-1]) (1<=k<=i-1)

【复杂度】

时间复杂度O(kn),空间可以用滚动数组,为O(1)

【AC】

 class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int len=prices.size();
if(len== || len==) return ;
if(k==) return ;
if(k>=len/){
int ans=;
for(int i=;i<len;i++){
ans+=max(,prices[i]-prices[i-]);
}
return ans;
}
vector<int> local,global;
local.resize(len);
global.resize(len);
for(int i=;i<len;i++){
local[i]=global[i]=;
}
for(int j=;j<=k;j++){
for(int i=;i<len;i++){
local[i]=max(local[i-]+prices[i]-prices[i-],global[i-]);
}
for(int i=;i<len;i++){
global[i]=max(global[i-],local[i]);
}
}
int ans=global[len-];
return ans;
}
};

local即为dp,表示局部最优解,global表示全局最优解

注意要特判k>=n/2,leetcode没有给出数据范围,k很大时会tle或mle,k若大于n/2,相当于可以无限次买卖,贪心就可以。