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

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】

 1 class Solution {
 2 public:
 3     int maxProfit(int k, vector<int>& prices) {
 4         int len=prices.size();
 5         if(len==0 || len==1) return 0;
 6         if(k==0) return 0;
 7         if(k>=len/2){
 8             int ans=0;
 9             for(int i=1;i<len;i++){
10                 ans+=max(0,prices[i]-prices[i-1]);
11             }
12             return ans;
13         }
14         vector<int> local,global;
15         local.resize(len);
16         global.resize(len);
17         for(int i=0;i<len;i++){
18             local[i]=global[i]=0;
19         }
20         for(int j=1;j<=k;j++){
21             for(int i=1;i<len;i++){
22                 local[i]=max(local[i-1]+prices[i]-prices[i-1],global[i-1]);
23             }
24             for(int i=1;i<len;i++){
25                 global[i]=max(global[i-1],local[i]);
26             }
27         }
28         int ans=global[len-1];        
29         return ans;
30     }
31 };
View Code

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

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

posted @ 2018-04-26 13:03  shulin15  阅读(145)  评论(0编辑  收藏  举报