leetcode -- Best Time to Buy and Sell Stock IV --难点要看

来源:互联网 发布:在淘宝上怎么看淘宝店 编辑:程序博客网 时间:2024/06/03 22:39

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/

思路1 买或者卖都算一次交易

思路就是从prices中最多挑选出2*k个数

参考:
http://bookshadow.com/weblog/2015/02/18/leetcode-best-time-to-buy-and-sell-stock-iv/
http://www.cnblogs.com/maples7/p/4350047.html

思路: dp[j] = max(dp[j], dp[j - 1] + prices[i] * [1, -1][j % 2]). j表示第j次交易,可以是买也可以是卖。

注意:
- 当 2*k >= size 时,k 的限制已经形同虚设了,操作数限制已经可以覆盖到每一天都允许操作,这种情况下还用上述DP效率太低,可以改为没有k限制的贪心版本
- None比任何数值都小, 在python中当做无穷小
- j 从min(2 * k, i + 1),对于i+1<2k(2k就是dp的长度)最多只可能进行i+1次交易。例如,i = 0, 只有一个price[0],那么要么买,要么卖(这里卖可以理解为依据在price[-1]用无穷大的价格买入了),或者不操作。所以更新dp[1]. 当i =1的时候,此时,对应的price[1], 则又要利用上一次的dp[1]来更新dp[2], 然后再一次更新dp[1]。当i = 3的时候,利用上一次的dp[2]来更新dp[3], 然后有利用上一次的dp[1]来更新dp[2],……….;当i = 4时,循环继续。知道i + 1> 2k了,i越界了dp,就只能从i = 2*k来更新了

class Solution:    # @return an integer as the maximum profit     def maxProfit(self, k, prices):        size = len(prices)        if k > size / 2:            return self.quickSolve(size, prices)        dp = [None] * (2 * k + 1)        dp[0] = 0        for i in range(size):            for j in range(min(2 * k, i + 1) , 0 , -1):                dp[j] = max(dp[j], dp[j - 1] + prices[i] * [1, -1][j % 2])        return max(dp)    def quickSolve(self, size, prices):        sum = 0        for x in range(size - 1):            if prices[x + 1] > prices[x]:                sum += prices[x + 1] - prices[x]        return sum

思路2 一次交易包括买和卖

思路:

http://blog.csdn.net/foreverling/article/details/43911309

  • 一次交易包括买和卖
  • i天之前进行j次交易。这j次交易可能还可以包括第j+1次的买入。一种极端的情况就是第j次的卖出在第i天,并且就在这一天又进行了第j+1次买入了。因为第i天只有一个价格price[i],第i天卖掉,第i天又买入第i+1天卖出,相当于第i天没卖掉,第i+1天卖出。这样从最大收益的角度来说,本来需要2次交易得到的收益,1次交易就行。

参考http://liangjiabin.com/blog/2015/04/leetcode-best-time-to-buy-and-sell-stock.html

传统的动态规划我们会这样想,到第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天当天本身也有交易呢(也就是说第i-1天刚卖出了股票,然后又买入等到第i天再卖出),那么这两次交易就可以合为一次交易,这样profit[i – 1][j – 1] + diff实际上只进行了j-1次交易,而不是最多可以的j次,这样得到的最大收益就小了。

其中“当第i天的价格高于第i-1天(即diff > 0)时,那么可以把这次交易(第i-1天买入第i天卖出)跟第i-1天的交易(卖出)合并为一次交易”,这里的意思就是说因为price[i-1]是i-1那天的股票价格,因为这一天股票价格只有price[i-1]这一个值,所以在m< i - 1天买入,i-1天卖出,然后同时又在i-1天买入的话,在第i天卖出,等价于在m天买入,在第i天卖出。这里本来是算当第i天有卖出,profit[i-1][j-1],i-1天之前有j-1次交易(不包括为了第i天卖出而进行的买入操作,因为只有在买入和卖出都进行之后才算一次交易),然后在第i天卖出又算一次交易,总共j次交易的。但其实这里等价于j - 1次交易,即等价于在m天买入,在第i天卖出,所以这样不对。

其余思路的ref:

我们需要维护如下两个量:
global[i][j]:当前到达第i天最多可以进行j次交易,所得到的最大利润。
local[i][j]:当前到达第i天最多可以进行j次交易,而且最后一次交易在当天卖出,所得到的最大利润。
状态转移方程:
global[i][j] = max(local[i][j], global[i-1][j])
上述方程比较两个量的大小:①当前局部最大值;②过往全局最大值。
local[i][j] = max(global[i-1][j-1] + max(diff, 0), local[i-1][j] + diff)
上述方程比较两个量的大小:
①全局到i-1天进行j-1次交易,然后加上今天的交易(如果今天的交易赚钱的话)。
②取局部第i-1天进行j次交易,然后加上今天的差值(local[i-1][j]是第i-1天卖出的交易,它加上diff后变成第i天卖出,并不会增加交易次数。无论diff是正还是负都要加上,否则就不满足local[i][j]必须在最后一天卖出的条件了)

思路3 很牛逼的思路

http://maskray.me/blog/2015-03-27-leetcode-best-time-to-buy-and-sell-stock-iv

0 0
原创粉丝点击