Best Time to Buy and Sell Stock IV(DP解法,o(kn)时间,o(k)空间)

来源:互联网 发布:网络播放器安装电视猫 编辑:程序博客网 时间:2024/05/16 10:31

Leetcode 上Best Time to Buy and Sell Stock IV解题思路:

此解法主要参考http://blog.csdn.net/linhuanmars/article/details/23236995#cpp上的思路, 但是博主的递归式不是很好理解,因此加上自己的理解,希望对后来者有所帮助, 第一次这么认真的写博客,如发现问题或者理解错误,欢迎批评指正,谢谢!

DP解法:
假设prices(0) 为第 1 天, 建立两个数组,一个为local[i][j] (从第 1 到 第 i天交易 j 次,并且最后一次卖出为第 i 天的最大利润), 另一个为 global[i][j] (从第 1 到第 i 天交易 j 次的最大利润)。可建立如下递归式:

global[i][j]=max(local[i][j],global[i-1][j]);

global[i][j] 可以分成两种情况:
1. 最后一次交易为最后一天,最大利润则为 local[i][j];
2. 最后一次交易不是最后一天, 因此所有 j 次交易在 第 1 到第 i - 1 天内完成,因此为global[i - 1][j]。
取两者中较大者。

同时需要DP计算local 数组,建立如下递归式(diff = prices[i] - prices[i - 1]):

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

同样,local[i][j] 的计算分为两种情况:
1. 最后一次买的时间为第 i - 1 或者第 i 天, 要保证local[i][j] 最大,则第i - 1 天以前买卖的 j - 1 次必须有最大利润,同时,如果diff > 0, 则最后一次的利润取diff, 如果diff < 0, 则取 0, 即第 i 天买, 第 i 天卖。
2. 最后一次买的时间为第 i - 1 天以前,同时最后一次卖必须为第 i 天(local 数组的定义), 同时可以分为两部分利润, 第一部分为前i - 1天的利润和第 i - 1 天到第 i 天的利润。要保证local[i][j] 最大, 则必须保证第一部分利润为最大,第二部分利润是不变的,为diff, 第一部分利润的最大值就相当于local[i - 1][j]。

观察上面数组,递归式中计算第 i 天时实际使用的数据只有第 i - 1天的数据, 因此可以使用一维数组来代替, 建立递归式如下:

local[j] = max(global[j - 1] + max(diff, 0), local[j] + diff);global[j] = max(local[j], global[j]);

这里存在一个小技巧,求第 local[i] 和 global[i] 时,采用从上往下循环,因此递归式中的第一个递归式中 等式右边的global[j - 1] 即为二维数组的global[i - 1][j - 1], local[j] 对应local[i - 1][j], 第二个式中等式右边的local[i]因为在第一个式中已经算出新值, 因此对应local[i][j], 而global[j] 对应 global[i - 1][j].

源代码如下(这里需要考虑 k > prices.size()的情况, 因为对于 n = prices.size() 最多只能产生 n - 1 次能产生利润的交易, 即在不同天内买卖才有可能利润, 因此当交易次数大于n时, 则和 Best Time to Buy and Sell Stock II 一样):

class Solution {public:int maxProfitII(vector<int>& prices) {        int maxSum = 0, currSum = 0, tmp;        for(int i = 1; i < prices.size(); ++i) {            tmp = currSum;            currSum += prices[i] - prices[i - 1];            if(currSum < tmp) {                maxSum += tmp;                currSum = 0;            }        }        if(currSum > 0)            maxSum += currSum;        return maxSum;    }    int maxProfit(int k, vector<int>& prices) {        if(k < 0 || prices.empty())            return 0;         int n = prices.size();        if(k > n)            return maxProfitII(prices);        vector<int> global(k + 1, 0), local(k + 1, 0);        int diff;        for(int i = 1; i < n; ++i) {            diff = prices[i] - prices[i - 1];            for(int j = k; j >= 1; --j) {                local[j] = max(global[j - 1] + max(diff, 0), local[j] + diff);                global[j] = max(local[j], global[j]);            }        }        return global[k];    }};
1 0
原创粉丝点击