天天看点

[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.

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).

思路:

这道题目自己没有独立做出来,我在网上参考了两种最好的解法,这里和大家分享。

1、记录局部最优解和全局最优解的动态规划法:用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]);

其中的local[i-1][j] + diff就是为了避免第i天交易和第i-1天交易合并成为一次交易而少一次交易收益。算法的时间复杂度是O(n^2),空间复杂度也是O(n^2)。不过由于local和global的递推公式只和它临近的元素有关,所以目测空间复杂度还可以进一步降低到O(n)。这里偷个懒,不弄了。

2、记录买入卖出的动态规划法:可以记录k次交易每次买入之后和卖出之后最大的利润。第i次买操作买下当前股票之后剩下的最大利润为第(i-1)次卖掉股票之后的利润 - 当前的股票价格,状态转移方程为:buys[i] = max(sells[i - 1] - current_price, buys[i]). 第i次卖操作卖掉当前股票之后剩下的最大利润为第i次买操作之后剩下的利润 + 当前的股票价格。状态转移方程为:sells[i] = max(buys[i] + current_price, sells[i])。最终所求即为sells[k]。

代码:

1、记录局部最优解和全局最优解的动态规划法:

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        if(prices.size() < 2) {
            return 0;
        }
        int days = prices.size();
        if(k >= days / 2) {
            return maxProfit(prices);
        }
        vector<vector<int>> local(days, vector<int>(k + 1, 0));
        vector<vector<int>> global(days, vector<int>(k + 1, 0));
        for(int i = 1; i < days; ++i) {
            int diff = prices[i] - prices[i - 1];
            for(int j = 1; j <= k; ++j) {
                local[i][j] = max(global[i-1][j-1], local[i-1][j] + diff);
                global[i][j] = max(global[i-1][j], local[i][j]);
            }
        }
        return global[days - 1][k];
    }
private:
    int maxProfit(vector<int>& prices) {
        int max_profit = 0;
        for(int i = 1; i < prices.size(); ++i) {
            if(prices[i] > prices[i-1]) {
                max_profit += prices[i] - prices[i-1];
            }
        }
        return max_profit;
    }
};
           

2、记录买入卖出的动态规划法:

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        if(prices.size() < 2) {
            return 0;
        }
        int days = prices.size(), ret = 0;
        if(k >= days / 2) {
            return maxProfit(prices);
        }
        vector<int> buys(days + 1, INT_MIN);
        vector<int> sells(days + 1, 0);
        for (int i = 0; i < days; ++i) {
            for (int j = 1; j <= k; ++j) {
                buys[j] = max(sells[j - 1] - prices[i], buys[j]);
                sells[j] = max(buys[j] + prices[i], sells[j]);
            }
        }
        return sells[k];
    }
private:
    int maxProfit(vector<int>& prices) {
        int max_profit = 0;
        for(int i = 1; i < prices.size(); ++i) {
            if(prices[i] > prices[i-1]) {
                max_profit += prices[i] - prices[i-1];
            }
        }
        return max_profit;
    }
};