今日任务:
1)123.买卖股票的最佳时机III
2)188.买卖股票的最佳时机IV
3)复习day18
123.买卖股票的最佳时机III
题目链接:123. 买卖股票的最佳时机 III - 力扣(LeetCode)
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成两笔交易。 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 示例 1: 输入:prices = [3,3,5,0,0,3,1,4] 输出:6 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3。 示例 2: 输入:prices = [1,2,3,4,5] 输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 示例 3: 输入:prices = [7,6,4,3,1] 输出:0 解释:在这个情况下, 没有交易完成, 所以最大利润为0。 示例 4: 输入:prices = [1] 输出:0 提示: 1 <= prices.length <= 10^5 0 <= prices[i] <= 10^5
文章讲解:代码随想录 (programmercarl.com)
视频讲解:动态规划,股票至多买卖两次,怎么求? | LeetCode:123.买卖股票最佳时机III哔哩哔哩bilibili
思路:
这个问题可以通过动态规划来解决。我们可以定义四个状态变量来表示不同的情况:
buy1
:表示完成第一笔交易后持有股票的最大利润。sell1
:表示完成第一笔交易后不持有股票的最大利润。buy2
:表示完成第二笔交易后持有股票的最大利润。sell2
:表示完成第二笔交易后不持有股票的最大利润。对于每一天,我们可以有四种操作:
- 保持持有状态,即不卖出,这样利润不变。
- 卖出股票,这样我们的利润将增加当前股票的价格。
- 买入股票,这样我们的利润将减少当前股票的价格。
我们的目标是选择操作使得最终的利润最大化。因此,我们可以通过比较这三种操作的结果来更新状态变量
buy1
、sell1
、buy2
和sell2
。具体步骤如下:
- 首先,我们初始化四个状态变量:
buy1
初始化为第一天的价格的相反数,因为在第一天买入股票。sell1
初始化为 0,因为在第一天不持有股票。buy2
初始化为第一天的价格的相反数,因为在第一天买入股票。sell2
初始化为 0,因为在第一天不持有股票。- 然后,我们遍历每一天的股票价格,对于每一天,我们都更新四个状态变量:
- 对于
buy1
,我们可以选择保持持有状态(即不买入),或者买入股票。我们选择较大的值更新buy1
。- 对于
sell1
,我们可以选择保持不持有状态(即不卖出),或者卖出股票。我们选择较大的值更新sell1
。- 对于
buy2
,我们可以选择保持持有状态(即不买入),或者买入股票。我们选择较大的值更新buy2
。- 对于
sell2
,我们可以选择保持不持有状态(即不卖出),或者卖出股票。我们选择较大的值更新sell2
。- 最终,我们返回
sell2
,因为在最后一天,我们希望不持有股票以获取最大利润。这样,我们通过动态规划来解决了问题,时间复杂度为 O(n),其中 n 是股票价格数组的长度。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
# 如果价格数组为空,则返回0
if not prices:
return 0
# 初始化第一笔交易买入和卖出的最大利润
buy1 = -prices[0] # 第一笔交易买入时持有股票,初始化为第一天的股票价格的相反数
sell1 = 0 # 第一笔交易卖出后不持有股票,初始化为0
# 初始化第二笔交易买入和卖出的最大利润
buy2 = -prices[0] # 第二笔交易买入时持有股票,初始化为第一天的股票价格的相反数
sell2 = 0 # 第二笔交易卖出后不持有股票,初始化为0
# 遍历股票价格数组
for price in prices[1:]:
# 更新第一笔交易买入和卖出的最大利润
buy1 = max(buy1, -price) # 第一笔交易买入时持有股票,取当前持有和之前持有的最大值
sell1 = max(sell1, buy1 + price) # 第一笔交易卖出后不持有股票,取当前不持有和之前不持有的最大值
# 更新第二笔交易买入和卖出的最大利润
buy2 = max(buy2, sell1 - price) # 第二笔交易买入时持有股票,取当前持有和之前持有的最大值
sell2 = max(sell2, buy2 + price) # 第二笔交易卖出后不持有股票,取当前不持有和之前不持有的最大值
return sell2 # 返回完成两笔交易后不持有股票的最大利润
188.买卖股票的最佳时机IV
题目链接:188. 买卖股票的最佳时机 IV - 力扣(LeetCode)
给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 示例 1: 输入:k = 2, prices = [2,4,1] 输出:2 解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2。 示例 2: 输入:k = 2, prices = [3,2,6,5,0,3] 输出:7 解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4。随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。 提示: 0 <= k <= 100 0 <= prices.length <= 1000 0 <= prices[i] <= 1000
文章讲解:代码随想录 (programmercarl.com)
视频讲解:动态规划来决定最佳时机,至多可以买卖K次!| LeetCode:188.买卖股票最佳时机4哔哩哔哩bilibili
思路:
- 首先检查输入的 prices 数组的长度是否小于2,如果是,则直接返回0,因为不可能完成交易。
- 接着判断如果 k 大于等于数组长度的一半,说明可以进行无限次交易(因为一次交易至少需要两天),那么可以直接使用贪心算法来解决问题,调用
maxProfitGreedy
函数即可。- 如果 k 小于数组长度的一半,则进入动态规划解决问题。
- 动态规划的状态
dp
是一个长度为 2k+1 的数组,其中dp[2*i+1]
表示在第 i 次交易后持有股票的最大利润,dp[2*i+2]
表示在第 i 次交易后不持有股票的最大利润。- 初始化时,对于每一次交易 i,初始化
dp[2*i+1]
为第一天的股票价格的负值,表示第一天购买股票的情况。而dp[2*i+2]
则初始化为0,表示不持有股票时的利润为0。- 遍历价格数组中的每一天,对于每一次交易 i,更新
dp[2*i+1]
和dp[2*i+2]
的值:
- 对于
dp[2*i+1]
,表示在第 i 次交易后持有股票的最大利润,更新为前一天持有股票利润dp[2*i+1]
和当前股票价格 price 的较大值。- 对于
dp[2*i+2]
,表示在第 i 次交易后不持有股票的最大利润,更新为前一天不持有股票利润dp[2*i+2]
和前一次持有股票利润加上当前股票价格 price 的较大值。- 最后返回
dp[-1]
,即完成了k次交易后不持有股票的最大利润。
class Solution:
def maxProfit(self, k: int, prices: List[int]) -> int:
n = len(prices)
if n < 2:
return 0
# 如果k超过了天数的一半,那么相当于可以进行无限次交易,因此可以直接返回贪心解法的结果
if k >= n // 2:
return self.maxProfitGreedy(prices)
# 初始化
dp = [0]*(2*k+1)
for i in range(k):
dp[2*i+1]=-prices[0]
for price in prices[1:]:
for i in range(k):
dp[2*i+1] = max(dp[2*i+1],dp[2*i]-price)
dp[2*i+2] = max(dp[2*i+2],dp[2*i+1]+price)
return dp[-1]
def maxProfitGreedy(self, prices: List[int]) -> int:
profit = 0
for i in range(1, len(prices)):
if prices[i] > prices[i - 1]:
profit += prices[i] - prices[i - 1]
return profit