题目一:leetcode122.买卖股票的最佳时机
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
思路1:
贪心:只要今天比明天小就买入,然后在第二天卖出。
解答1:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
res=0
n=len(prices)
for i in range(1,n):
t=prices[i]-prices[i-1]
if t>0:
res+=t
return res
思路2:
动态规划:略,见代码解析
解答2:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices:
return 0
n=len(prices)
dp=[[0]*2 for _ in range(n)]
#dp[i][0]:第i天不持有股票时的利润值
#dp[i][1]:第i天持有股票时的利润值
dp[0][0]=0
dp[0][1]=-prices[0]
for i in range(1,n):
#dp[i][0]:昨天未持有 or 昨天持有今天卖掉
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i])
#dp[i][1]:昨天就持有 or 昨天未持有今天买入
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i])
return dp[n-1][0]
题目二:leetcode188.买卖股票的最佳时机
给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
解答:
方法一:
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
if not prices:
return 0
n=len(prices)
k=min(k,n//2)
#用buy[i][j] 表示对于数组prices[0..i] 中的价格而言,进行恰好j笔交易,并且当前手上持有一支股票,这种情况下的最大利润;
#用sell[i][j] 表示对于数组prices[0..i] 中的价格而言,恰好进行j笔交易,并且当前手上不持有股票,这种情况下的最大利润。
buy=[[0]*(k+1) for _ in range(n)]
sell=[[0]*(k+1) for _ in range(n)]
buy[0][0],sell[0][0]=-prices[0],0
#对利润值进行初始化,将其设为最小
for i in range(1, k + 1):
buy[0][i] = sell[0][i] = float("-inf")
for i in range(1, n):
#buy[i][0]:i-1持有但目前还未卖出,i-1不持有且在i买入
buy[i][0] = max(buy[i - 1][0], sell[i - 1][0] - prices[i])
for j in range(1, k + 1):
#对于buy[i][j],我们考虑当前手上持有的股票是否是在第i天买入的
buy[i][j] = max(buy[i - 1][j], sell[i - 1][j] - prices[i])
#对于sell[i][j],我们考虑股票是否是在第i天卖出的
sell[i][j] = max(sell[i - 1][j], buy[i - 1][j - 1] + prices[i]);
return max(sell[n - 1])
方法二:
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
n=len(prices)
if n==0:
return 0
#dp[i][j]:j为奇数代表买入,j为偶数代表卖出,j有2k+1种状态
dp=[[0]*(2*k+1) for _ in range(n)]
#初始化
for j in range(1,2*k,2):
dp[0][j]=-prices[0]
#状态转移
for i in range(1,n):
for j in range(0,2*k,2):
dp[i][j+1]=max(dp[i-1][j+1],dp[i-1][j]-prices[i])
dp[i][j+2]=max(dp[i-1][j+2],dp[i-1][j+1]+prices[i])
return dp[n-1][2*k]
方法三:在方法二的基础上做了空间优化
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
n=len(prices)
if n==0:
return 0
#dp[i][j]:j为奇数代表买入,j为偶数代表卖出,j有2k+1种状态
dp=[0]*(2*k+1)
#初始化
for j in range(1,2*k,2):
dp[j]=-prices[0]
#状态转移
for i in range(1,n):
for j in range(0,2*k,2):
dp[j+1]=max(dp[j+1],dp[j]-prices[i])
dp[j+2]=max(dp[j+2],dp[j+1]+prices[i])
return dp[2*k]
题目三:leetcode123.买卖股票的最佳时机III
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
思路:
因为最多只允许进行两次交易,所以每一天的状态只有5种,即:
1.没有进行任何交易
2.只进行过一次买操作
3.完成一笔交易
4.在完成了一次交易后,又进行了一次买操作
5.完成两笔交易
那么对于边界条件,我们考虑第 i=0 天时的四个状态:
1.以prices[0] 的价格买入股票,因此buy1=-prince[0] ;
2.即为在同一天买入并且卖出,因此sell1=0;
3.在同一天买入并且卖出后再以prices[0] 的价格买入股票,因此buy2 =−prices[0];
4.同理可得sell2 =0
解答:
方法一:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
#buy1:只进行过一次买操作的最大利润
#buy2:在完成了一次交易后,又进行了一次买操作的最大利润
buy1 = buy2 = -prices[0]
#sell1:完成一笔交易时的最大利润
#sell2:完成两笔交易时的最大利润
sell1 = sell2 = 0
for i in range(1, n):
buy1 = max(buy1, -prices[i])
sell1 = max(sell1, buy1 + prices[i])
buy2 = max(buy2, sell1 - prices[i])
sell2 = max(sell2, buy2 + prices[i])
return sell2
方法二:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
#0:无操作
#1:第一次买入
#2:第一次卖出
#3:第二次买入
#4:第二次卖出
n=len(prices)
dp=[[0]*5 for _ in range(n)]
dp[0][1]=-prices[0]
dp[0][3]=-prices[0]
for i in range(1,n):
dp[i][0]=dp[i-1][0]
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i])
dp[i][2]=max(dp[i-1][2],dp[i-1][1]+prices[i])
dp[i][3]=max(dp[i-1][3],dp[i-1][2]-prices[i])
dp[i][4]=max(dp[i-1][4],dp[i-1][3]+prices[i])
return dp[n-1][4]
class Solution:
def maxProfit(self, prices: List[int]) -> int:
#动态规划
n=len(prices)
#dp[i][j]:第i天为状态j时的最大利润
#j=0:没有操作
#j=1:第一次持有
#j=2:第一次不持有
#j=3:第二次持有
#j=4:第二次不持有
dp=[0]*5
dp[0][1]=-prices[0]
dp[0][3]=-prices[0]
res=0
for i in range(1,n):
#第i天没有操作,前一天也必然没有操作
dp[i][0]=dp[i-1][0]
#第i天第一次持有股票的最大利润
dp[i][1]=max(dp[i-1][1],-prices[i])
dp[i][2]=max(dp[i-1][2],dp[i][1]+prices[i])
##第i天第二次持有股票的最大利润
dp[i][3]=max(dp[i-1][3],dp[i][2]-prices[i])
dp[i][4]=max(dp[i-1][4],dp[i][3]+prices[i])
return dp[n-1][4]
方法三:空间优化
class Solution:
def maxProfit(self, prices: List[int]) -> int:
#0:无操作
#1:第一次买入
#2:第一次卖出
#3:第二次买入
#4:第二次卖出
n=len(prices)
dp=[0]*5
dp[1]=-prices[0]
dp[3]=-prices[0]
for i in range(1,n):
dp[0]=dp[0]
dp[1]=max(dp[1],dp[0]-prices[i])
dp[2]=max(dp[2],dp[1]+prices[i])
dp[3]=max(dp[3],dp[2]-prices[i])
dp[4]=max(dp[4],dp[3]+prices[i])
return dp[4]