Leetcode(W9):188. Best Time to Buy and Sell Stock IV(动态规划)

来源:互联网 发布:互联网java 技术路线 编辑:程序博客网 时间:2024/05/16 03:40

leetcode中Best Time to Buy and Sell Stock买卖股票的最佳时间总共有5道类型题。
参考这位大牛的博客:传送门


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

题意:

给定一个数组,下标代表第几天,元素值即为当天可买进或卖出的股票价格,现在设定我们最多能进行K次交易(注意每次卖都必须卖光,不能说我今天1块钱买入明天2块钱卖出,后天又能3块钱卖出,一次交易只能一次买对应一次卖),谋取最大利益然后输出这个最大利益。

思路:

我们之前用动态规划,是不是就觉得这种题目应该存在通解的呢,通解能方便计算当题目条件为“能进行K次交易”时的情景。如果我们能把通解即最多能进行K次交易解决了。
定一个数组global[i][j]为第一天到第i天可以最多进行j次交易的最好的利润,再定一个数组local[i][j]为第一天到第i天可以最多进行j次交易且最后一次卖出必须发生在第i天这天的最好的利润。
那么推出今天的全局最优只需要比较两种情况,要么是刚好今天卖出去赚了的局部最优,要么今天卖出去会亏,所以就仍是昨天的全局最优,视这两者谁大而定,所以全局数组递推式为
global[i][j]=max(local[i][j],global[i-1][j])
而今天的局部最优则限定了最后一次交易必须在今天卖出,仍然要比较两种情况:
一、昨天进行j-1次交易的全局最优,加上最后一次交易在今天卖出所得的利润diff,关于diff也有两种情况:
①、如果最后一次交易今天卖出但又不是今天买进的,即最后一次交易利润大于0,那么diff就是prices[i + 1] - prices[i];
②、如果条件①里不存在利润大于0的情况,比如股票一直下跌,那么最后一次交易只能是今天买今天卖,此时diff为0
所以diff直接取①和②中的最大值即可
二、最后一次交易发生在昨天的局部最优,然后我们把昨天的“卖出”调到今天,并且不管赚还是亏都得今天卖出,所以不需要像上面那样比较,局部最优直接加上差价prices[i + 1] - prices[i]即可,所以diff仍然是prices[i + 1] - prices[i]。
最后,今天的局部最优取一和二中的最大值即可。
局部数组的递推式为
local[i][j]=max(global[i-1][j-1]+max(diff,0),local[i-1][j]+diff)
发现没有,因为每一天都存在全局最优和局部最优两条路走,所以每次递推都是在跟昨天的全局最优和局部最优作比较,然后贪心地选择最优的那个。
注意:这道题有一种特殊情况是跟Best Time to Buy and Sell Stock II一模一样的,如果k的值大于等于prices的天数,此时你是可以做到第一天买,然后接下来只要一出现利润就卖出去的操作的(因为从第二天开始每一天你都能卖出再买进),这道题也就跟II一模一样了。所以应该采取II里的解法,II的思路传送门在此。

操作:

local[k]表示进行k次交易的局部最优
global[k]表示进行k次交易的全局最优,我们要求的值即为global[k]
i从第一天遍历到最后一天,j从k遍历到1
由于先更新local,所以global可以直接 max(global[j], local[j]);这里第一个参数global[j]正好还是昨天的,而第二个参数local[j]正好是今天的。
而对于local,local中global[j-1]和local[j]刚好也是昨天(i-1的时候)算出来的,所以都不用二维数组global[i-1][j-1],local[i-1][j]来计算那么麻烦了,因为取昨天的值再覆盖掉就行了。
用一维数组来代替二维数组,可以极大的节省了空间,由于覆盖的顺序关系,我们需要j从2到1,这样可以取到正确的g[j-1]值,而非已经被覆盖过的值

2. 代码

int solveMaxProfit(vector<int>& prices) {    int profit = 0;    for (int i = 1; i < prices.size(); i++) {        if (prices[i] - prices[i-1] > 0) {            profit += prices[i] - prices[i-1];        }    }    return profit;}int maxProfit(int k, vector<int>& prices) {    if (prices.size() == 0) {        return 0;    }    if (prices.size() <= k) {//当Best Time to Buy and Sell Stock II来做         return solveMaxProfit(prices);    }    int local[k+1] = {0};    int global[k+1] = {0};    for (int i = 0; i < prices.size()-1; i++) {        int diff = prices[i+1] - prices[i];        for (int j = k; j >= 1; j--) {            local[j] = max(global[j-1] + max(diff, 0), local[j]+diff);            global[j] = max(global[j], local[j]);        }    }    return global[k];}
阅读全文
0 0
原创粉丝点击