Best Time to Buy and Sell Stock III

Posted xiaoyunjun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Best Time to Buy and Sell Stock III相关的知识,希望对你有一定的参考价值。

技术图片

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

这里有一个关键点:在某一天买入股票,并在当天卖出股票是合法的(支持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\\ \\beginaligned & dp[i][j-1] \\\\ & dp[i-1][m] + prices[j] - prices[m], m\\in [0,1,...,j-1] \\endaligned \\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的主要内容,如果未能解决你的问题,请参考以下文章

最强解析面试题:best-time-to-buy-and-sell-stock

最强解析面试题:best-time-to-buy-and-sell-stock

121. Best Time to Buy and Sell Stock

122. Best Time to Buy and Sell Stock II

123. Best Time to Buy and Sell Stock III***

LeetCode 121. Best Time to Buy and Sell Stock