leetcode 188---Best Time to Buy and Sell Stock IV

问题描述:

Say you have an array for which the ith element is the price of a given stock on day i.
给你一个数组,里边的第i个元素存储的是股票在第i天的价格
Design an algorithm to find the maximum profit. You may complete at most k transactions.
允许最多完成k次交易(买进卖出k次),设计算法找出最大收益。
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
不能同时进行多次交易(在你再一次买进之前必须先卖出)。

问题求解:

特殊动态规划法。传统的动态规划我们会这样想,到第i天时进行j次交易的最大收益,要么等于到第i-1天时进行j次交易的最大收益(第i天价格低于第i-1天的价格),要么等于到第i-1天时进行j-1次交易,然后第i天进行一次交易(第i天价格高于第i-1天价格时)。于是得到动规方程如下(其中diff = prices[i] – prices[i – 1]):

profit[i][j] = max(profit[i – 1][j], profit[i – 1][j – 1] + diff)

看起来很有道理,但其实不对,为什么不对呢?因为diff是第i天和第i-1天的差额收益,如果第i-1天当天本身也有交易呢,那么这两次交易就可以合为一次交易,这样profit[i – 1][j – 1] + diff实际上只进行了j-1次交易,而不是最多可以的j次,这样得到的最大收益就小了。

那么怎样计算第i天进行交易的情况的最大收益,才会避免少计算一次交易呢?我们用一个局部最优解和全局最有解表示到第i天进行j次的收益,这就是该动态规划的特殊之处。

定义local[i][j]为在到达第i天时最多可进行j次交易并且最后一次交易在最后一天卖出的最大利润,此为局部最优。global[i][j]为在到达第i天时最多可进行j次交易的最大利润,此为全局最优 。它们二者的关系如下:
(其中diff = prices[i] – prices[i – 1]

local[i][j] = max(global[i – 1][j – 1] + max(diff, 0), local[i – 1][j] + diff)
global[i][j] = max(global[i – 1][j], local[i][j])

局部最优值是比较前一天并少交易一次的全局最优加上大于0的差值,和前一天的局部最优
加上差值后相比,两者之中取较大值,而全局最优比较局部最优和前一天的全局最优。

其中的local[i – 1][j] + diff就是为了避免第i天交易和第i-1天交易合并成一次交易而少一次交易收益。
参考:
http://www.cnblogs.com/grandyang/p/4295761.html
http://www.cnblogs.com/grandyang/p/4295761.html
代码:时间O(n),空间O(k)

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n = prices.size();
        if(n <= 1){
            return 0;
        }
        //k大于天数时,退化成Best Time to Buy and Sell Stock II问题
        if(k >= n){
            return maxProfit2(prices);
        }
        vector<int> local(k+1);
        vector<int> global(k+1);
        //两层for循环实现二维数组,比如global[i][j]
        //可由i循环下的global[j]实现
        for(int i=1;i<n;i++){
            int diff = prices[i] - prices[i-1];
            for(int j=k;j>0;j--){
                local[j]=max(global[j-1]+max(diff,0),local[j]+diff);
                global[j]=max(global[j],local[j]);
            }
        }
        return global[k];
    }
    int maxProfit2(vector<int>& prices){
        int n = prices.size();
        int profit=0;
        int max_profit=0;
        for(int i=1;i<n;i++){
            if(prices[i] > prices[i-1]){
                profit=prices[i]-prices[i-1];
                max_profit += profit;
            }
        }
        return max_profit;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值