No.49-LeetCode188 - 动态规划-K次股票最大收益-很难

O(N^3) dp通用解法,会超时:
很多类似区间dp可以采用这个模版。

int maxProfit(int k, vector<int>& prices) {
    int N = prices.size();
    int K = min(k,N/2);
    int mx[N+1][N+1];
    int mn[N+1][N+1];
    int one[N+1][N+1];
    int dp[K+1][N+1];
    memset(mx,0,sizeof(mx));
    memset(mn,0,sizeof(mn));
    memset(one,0,sizeof(one));
    memset(dp,0,sizeof(dp));
    for(int i=0;i<N;i++) mx[i][i] = mn[i][i] = prices[i];
    for(int i=N-1;i>=0;i--){
        for(int j=i+1;j<N;j++){
            mx[i][j] = max(mx[i][j-1],prices[j]);
            mn[i][j] = min(mn[i][j-1],prices[j]);
        }
    }
    for(int l=0;l<N;l++){
        for(int r=l;r<N;r++){
            for(int t=l;t<r;t++){
                one[l][r] = max(one[l][r],mx[t+1][r] - mn[l][t]);
            }
        }
    }
    for(int t=1;t<=K;t++){
        for(int l=N-1;l>=0;l--){
            for(int r=l;r<N;r++){
                dp[t][l] = max(dp[t][l], one[l][r] + dp[t-1][r+1]); 
            }
        }
    }
    int ans = 0;
    for(int t=0;t<=K;t++) ans = max(ans,dp[t][0]);
    return ans;
}

对于股票比较特殊,有特殊处理方法:

初始手里面价格为0,
当买入时,相当于花费prices价格,
卖出时,相当于挣得prices价格。
这样处理的好处是状态可以叠加。
处于一个股票点时,后面股票走势的收益是固定的。
所以,当前股票点价格最高,那么最后得到的结果也是最优的。
所以,一道看似区间dp,实际上只是一道普通dp。

如果只能买卖一次,只需要维护一个值,来代表手中的最大价格。
遍历每个股票点,最后得到的就是利润。

如果可以买卖k次,只需要维护k个值,来代表k次交易后手中最大价格。

int maxProfit(int k, vector<int>& prices) {
    int n = prices.size();
    k = min(k,n/2);
    int f[k+1],g[k+1];
    memset(f,0,sizeof(f));
    memset(g,0xc0,sizeof(g));
    for(int i=0;i<n;i++){
        for(int j=1;j<=k;j++){
            f[j] = max(f[j],g[j] + prices[i]); // 此时卖出
            g[j] = max(f[j-1] - prices[i], g[j]); // 此时买入
        }
    } 
    return f[k];
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值