码迷,mamicode.com
首页 > 其他好文 > 详细

Best Time to Buy and Sell Stock III

时间:2019-06-09 23:50:31      阅读:119      评论:0      收藏:0      [点我收藏+]

标签:span   递推   max   list   方便   最大值   length   选择   self   

技术图片

该题相对之前两道题难了不少,做了两遍还是有点不熟。给定一个股票价格的数组,让你最多只能交易两次,求能够获得的最大利润。

这里有一个关键点:在某一天买入股票,并在当天卖出股票是合法的(支持t+0交易,不得不吐槽天朝t+1交易机制)。

举个例子[1,3,8],我们可以选择在第0天买入,然后第2天卖出。也可以在第0天买入,第1天卖出,然后又在第1天买入,最后再在第2天卖出。两种交易策略的利润是相同的。下面给出解决方案。

1.分治

这种办法相对简单一些,时间复杂度为o($n^2$)。做法很简单,就是遍历数组,当坐标为 i 时,分别求得prices[0-i]和prices[i-end]单次交易的最大利润,取两者和的最大值返回。这里就不给出代码了

2.动态规划

我们可以定义dp[i][j]为第i次交易,在第j天获得的最大利润(可以是在第j天卖出获得的利润,或者第j天之前的交易所获利润)。我们可以很简单获得如下递推公式:

$ dp[i][j] = max \left\{ \begin{aligned} & dp[i][j-1] \\ & dp[i-1][m] + prices[j] - prices[m], m\in [0,1,...,j-1] \end{aligned} \right. $

我们来解释这个公式,在第i轮交易过程中,如果第j天没有发生交易,那么到第j天为止,所获利润就是前一天的利润dp[i][j-1]。

另外,我们还需要做一轮遍历操作,获得这轮遍历的最大利润值。dp[i-1][m]也就是上一轮交易过程中,在第m天所获得的最大利润。这里包括两种情况:1. 第i-1轮交易没有在第m天卖出 2.第i-1轮交易在第m天卖出。其实两者都可以用上述代码解决。如果是第一种情况,那么这种情况很好理解,也就是我们遍历买入时间$$m\in [0,1,...,j-1]$$,并在第j天卖出所获得最大利润。对于第二种情况,也就是说在第m天卖出得到利润dp[i-1][m],然后我们再买入,相当于当天卖出,当天买入,然后在第j天卖出能够获得的利润。这种做法的时间复杂度也为o($n^2$)。这里给出代码:

 1 class Solution:
 2     def maxProfit(self, prices: List[int]) -> int:
 3         if not prices:
 4             return 0
 5         length = len(prices)
 6         if length == 1:
 7             return 0
 8         dp = [[0] * length for i in range(3)]
 9         for i in range(1,3):
10             #这里dp[i][j]指的是在第j天完成第i次交易
11             for j in range(0, length):
12                 for m in range(0, j):
13                     dp[i][j] = max(dp[i-1][m]+prices[j]-prices[m], dp[i][j])
14                 dp[i][j] = max(dp[i][j-1], dp[i][j])
15         return dp[-1][-1]

其实,如果我们画个图观察计算路径,有些计算是重复的。举个例子,在第1轮交易过程中,我们计算dp[1][3]时,需要遍历:

$dp[1][3] = dp[0][0]+prices[3]-prices[0] \\dp[1][3] = dp[0][1]+prices[3]-prices[1] \\ dp[1][3] = dp[0][2]+prices[3]-prices[2]$

找到上述3个式子中的最大利润值,其中prices[3]是一个定值。

计算dp[1][4]时,需要遍历:

$dp[1][4] = dp[0][0]+prices[4]-prices[0] \\dp[1][4] = dp[0][1]+prices[4]-prices[1] \\ dp[1][4] = dp[0][2]+prices[4]-prices[2] \\ dp[1][4] = dp[0][3]+prices[4]-prices[3]$

找到上述4个式子中的最大利润值,其中prices[4]是一个定值。

细心的童鞋可能已经发现了,在这个过程中,我们只需要最大化dp[i-1][m] - prices[m],将这个值保存下来,可以节省在第i轮交易过程中一些不必要的重复计算过程。

此时时间复杂度为o($n^2$), 代码如下:

 1 class Solution:
 2     def maxProfit(self, prices: List[int]) -> int:
 3         #动态规划解决这个问题,这道题两刷还是不会
 4         #主要是求出第一次交易和第二次交易后获得的最大利润
 5         #为了方便,第二次交易后得到的利润与第一次交易后得到的利润有关,而第一次交易后得到的利润与第0次交易得到的利润有关
 6         if not prices:
 7             return 0
 8         length = len(prices)
 9         if length == 1:
10             return 0
11         dp = [[0] * length for i in range(3)]
12         for i in range(1,3):
13             #在第j日买入时所获利润为temp_max
14             #这里dp[i][j]指的是在第j天完成第i次交易,[如果在第j天买入并卖出,收益为0]
15             temp_max = dp[i-1][0] - prices[0]
16             for j in range(0, length):
17                 temp_max = max(temp_max, dp[i-1][j] - prices[j])
18                 dp[i][j] = max(dp[i][j-1], temp_max+prices[j])
19         return dp[-1][-1]

 

Best Time to Buy and Sell Stock III

标签:span   递推   max   list   方便   最大值   length   选择   self   

原文地址:https://www.cnblogs.com/xiaoyunjun/p/10995049.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!