188 Best Time to Buy and Sell Stock IV [Leetcode]

44 篇文章 0 订阅

题目内容:

Say you have an array for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit.

You may complete at most k transactions. Note: You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

解题思路:
这是一个动态规划问题。首先分析问题与子问题之间的依赖关系。

问题可以分解成,如果已知在i天,最大交易次数为k次时的最大收益,如何求得在i+1天时,最大交易次数为k次的最大收益。最后一天一定是将股票卖出,但我们不能光考虑卖出股票的收益记录,因为卖出股票的收益基于上一次买入股票的收益。而在特定的某一天中,有三种操作状态:买股票,卖股票,什么也不做。一次连续的买卖构成一次交易操作。

为了计算收益而又能够不需要考虑天数差与收益之间的联系,在计算收益的时候,直接将某一日的交易金额作为收入。即在买入股票时,当天收益为股票价格的负数,卖出股票时,当天收益就是股票的价格。

因此,把状态转移方程写出来就是:
第i天中第k次买股票所得收益 = max{第i-1天中第k-1次卖股票所得收益-第i天的股价,第i-1天中第k次买股票所得收益}
第i天中第k次卖股票所得收益 = max{第i-1天中第k次买股票所得收益+第i天的股价,第i-1天中第k次卖股票所得收益}

用profit[i][k][2]存储第i天第k次交易所得的最大收益,最低维的二维数组用来存储第k次交易中买和卖分别对应的收益。由于当天这一天收益基于上一天,其实只需要用profit[k][2]来记录当前这一天收益的更新情况即可。

还有几个值得注意的地方是:
1. 因为第k次交易基于第k-1次交易的结果,为了防止结果被覆盖,采用从后向前(k->0)的顺序遍历更新收益。当然也可以用另一个数组先存起来再计算,但这会需要额外的空间。
2. 因为求第i天第k次卖的结果依赖于第i-1天第k次买的结果,如果先求第i天第k次买的结果会导致第i-1天第k次买的结果被覆盖。因此每次交易得先求卖结果再求买结果。
3. 由于边界检查需要检查数组是否越界,为了统一计算,将k次交易数组的大小设置成了k+1,第0个位置存放初始化数据,即profit[k][0] = INT_MIN,确保初始化买股票的金额一定会被更新(买股票时股票的价格小于INT_MAX),profit[k][1] = 0,确保卖股票的收益一定会被更新(卖股票时为了获取最大收益,收益一定为正)
4. 因为n天中股票最多交易n/2次,因此当k大于等于n/2时,问题退化为Best Time to Buy and Sell Stock II

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int size(prices.size());
        if(size <= 1 || k <= 0)
            return 0;
        if(k >= size/2)
            return bestProfit(prices);

        vector<vector<int>> profit(k+1, vector<int>(2, 0));
        for(int i = 0; i <= k; ++i)
            profit[i][0] = INT_MIN;

        for(int i = 0; i < size; ++i) {
            for(int j = k; j > 0; --j) {
                profit[j][1] = max(profit[j][1], profit[j][0]+prices[i]);
                profit[j][0] = max(profit[j][0], profit[j-1][1]-prices[i]);
            }
        }

        int result;
        for(int i = 1; i <= k; ++i) {
            result = max(result, profit[i][1]);
        }
        return result;
    }

    int bestProfit(vector<int>& prices) {
        int result(0);
        for(int i = 1; i < prices.size(); ++i) {
            int delta(prices[i] - prices[i-1]);
            if(prices[i] - prices[i-1] > 0) {
                result += delta;
            }
        }
        return result;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值