共6个问题:
分析:
- 只允许一次交易的最大收益(一次买进卖出)动态规划: dp[i] = max(dp[i-1], prices[i] - minval);
- 允许多次交易的最大收益(多次买进卖出)贪心算法:只要盈利就交易;
- 只允许有两次交易的最大收益(两次买进卖出)动态规划:
1) dp1[i] = max(dp[i-1], prices[i] - minval) 从前往后遍历,表示第1天到第i天之间的最大利润(通过是否在第i天卖出确认);
2) dp2[i] = max(dp[i+1], maxval - prices[i]) 从后往前遍历,表示第i天到最后一天之间的最大利润(通过是否在第i天买进确认);
3) res = max(dp1 + dp2),(dp1 + dp2)[i] 正好表示从第1天到最后一天经过两次交易的最大利润,我们的目标是知道令总利润最大的i。 - 只允许k次交易的最大收益(k次买进卖出)动态规划:
local[i][j]表示第i天进行了j笔交易,且第j笔是在第i天完成的的最大收益;
global[i][j]表示第i天进行了j笔交易的最大收益,是目前为止全局最优,不规定第j笔在哪天完成。则递推公式为:
1) local[i][j] = max(global[i-1][j-1]+max(0, prices[i]-prices[i-1]), local[i-1][j]+prices[i]-prices[i-1])
2) global[i][j] = max(local[i][j], global[i-1][j])
3) 双重循环,计算最后取global[-1][-1]
4) 注意当k大于天数时,直接用贪心算法。
https://blog.csdn.net/linhuanmars/article/details/23236995 - 有冷冻期的最大交易(一次买卖后需要冷冻一天)动态规划:
sell[i]表示截至第i天,最后一个操作是卖时的最大收益;
buy[i]表示截至第i天,最后一个操作是买时的最大收益;
cool[i]表示截至第i天,最后一个操作是冷冻期时的最大收益;
递推公式:
sell[i] = max(buy[i-1]+prices[i], sell[i-1]) (第一项表示第i天卖出,第二项表示第i天冷冻)
buy[i] = max(cool[i-1]-prices[i], buy[i-1]) (第一项表示第i天买进,第二项表示第i天冷冻)
cool[i] = max(sell[i-1], buy[i-1], cool[i-1])
https://www.cnblogs.com/grandyang/p/4997417.html - 有手续费的最大交易(每买卖一次都会扣除一次手续费) 动态规划
dp1[i]表示第i天手上有股票,dp2[i]表示第i天手上没有股票,递归方程:
1) dp1[i] = max(dp1[i-1], dp2[i-1] - prices[i]) (第二项表示在第i天买入股票)
2) dp2[i] = max(dp2[i-1], dp1[i-1] + prices[i] - fee) (第二项表示在第i天将股票卖出,需扣除手续费)
代码:
#买卖股票最佳时机I(只允许一次交易)
class Solution(object):
def maxProfit(self, prices):
n = len(prices)
if n == 0:
return 0
dp = [0 for _ in range(n)]
minval = prices[0]
for i in range(1, n):
dp[i] = max(dp[i-1], prices[i] - minval)
minval = min(minval, prices[i])
return dp[-1]
#买卖股票最佳时机II(允许多次交易)
class Solution:
def maxProfit(self, prices):
#贪心算法,只要出现盈利情况,就算作一次交易
n = len(prices)
if n == 0:
return 0
res = 0
for i in range(1,n):
res += max(0, prices[i]-prices[i-1])
return res
#买卖股票最佳时机III(只允许两次交易)
class Solution:
def maxProfit(self, prices):
n = len(prices)
if n < 2:
return 0
dp1 = [0 for _ in range(n)]
dp2 = [0 for _ in range(n)]
minval = prices[0]
maxval = prices[-1]
#前向
for i in range(1,n):
dp1[i] = max(dp1[i-1], prices[i] - minval)
minval = min(minval, prices[i])
#后向
for i in range(n-2,-1,-1):
dp2[i] = max(dp2[i+1], maxval - prices[i])
maxval = max(maxval, prices[i])
dp = [dp1[i] + dp2[i] for i in range(n)]
return max(dp)
#买卖股票最佳时机IV(只允许k次交易)
class Solution:
def maxProfit(self, k, prices):
if k <= 0 or len(prices) == 0:
return 0
if k > len(prices):
return self.greedy(prices)
l = [[0 for _ in range(k+1)] for _ in range(len(prices))]
g = [[0 for _ in range(k+1)] for _ in range(len(prices))]
for i in range(1,len(prices)):
diff = prices[i] - prices[i-1]
for j in range(1,k+1):
l[i][j] = max(g[i-1][j-1] + max(0, diff), l[i-1][j] + diff)
g[i][j] = max(l[i][j], g[i-1][j])
return g[-1][-1]
def greedy(self, prices):
res = 0
for i in range(1,len(prices)):
res += max(0, prices[i]-prices[i-1])
return res
#买卖股票最佳时机(含冷冻期)
class Solution:
def maxProfit(self, prices):
n = len(prices)
if n == 0:
return 0
sell = [0 for _ in range(n)]
buy = [0 for _ in range(n)]
cool = [0 for _ in range(n)]
buy[0] = -prices[0]
for i in range(1,n):
sell[i] = max(buy[i-1] + prices[i], sell[i-1])
buy[i] = max(cool[i-1] - prices[i], buy[i-1])
cool[i] = max(sell[i-1], buy[i-1],cool[i-1])
return sell[-1]
#买卖股票最佳时机(含手续费)
class Solution:
def maxProfit(self, prices, fee):
n = len(prices)
if n < 2:
return 0
dp1 = [0 for _ in range(n)]#第i天手上有股票时的最大收益
dp2 = [0 for _ in range(n)]#第i天手上无股票时的最大收益
dp1[0] = -prices[0]
for i in range(1,n):
dp1[i] = max(dp1[i-1], dp2[i-1] - prices[i])
dp2[i] = max(dp2[i-1], dp1[i-1] + prices[i] - fee)
return dp2[n-1]