0
点赞
收藏
分享

微信扫一扫

C++动态规划(背包问题)

后来的六六 2024-08-28 阅读 30

代码随想录训练营 Day41打卡 动态规划 part08

一、力扣121. 买卖股票的最佳时机

在这个问题中,我们需要计算在给定的股票价格数组 prices 中,最多只能进行一次交易(即一次买入和一次卖出)的情况下,能够获得的最大利润。为了实现这一点,我们使用动态规划的方法来模拟整个买卖过程。

我们定义两个状态:

  • dp[i][0] 表示第 i 天持有股票时能够获得的最大现金金额。
  • dp[i][1] 表示第 i 天不持有股票时能够获得的最大现金金额。

注意,“持有股票”不一定表示当天买入股票,也可能是之前买入的,并且持续持有到当天。同样地,“不持有股票”可以是当天卖出股票,或者之前已经卖出并且保持不持有状态。

持有股票时 (dp[i][0]):

如果第 i-1 天已经持有股票,那么保持现状:dp[i - 1][0]。
如果第 i 天买入股票,那么所得现金为 -prices[i]。
公式:dp[i][0] = max(dp[i - 1][0], -prices[i])

不持有股票时 (dp[i][1]):

如果第 i-1 天已经不持有股票,那么保持现状:dp[i - 1][1]。
如果第 i 天卖出股票,那么所得现金为 prices[i] + dp[i - 1][0]。
公式:dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
以示例输入:[7,1,5,3,6,4]为例,dp数组状态如下:
在这里插入图片描述
dp[5][1]就是最终结果。

为什么不是dp[5][0]呢?

因为本题中不持有股票状态所得金钱一定比持有股票状态得到的多!

代码实现

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        length = len(prices)
        if length == 0:
            return 0
        
        # 初始化 dp 数组,大小为 [length][2]
        # dp[i][0] 表示第 i 天持有股票时的最大现金
        # dp[i][1] 表示第 i 天不持有股票时的最大现金
        dp = [[0] * 2 for _ in range(length)]
        
        # 初始化第一天的状态
        dp[0][0] = -prices[0]  # 第 0 天买入股票
        dp[0][1] = 0  # 第 0 天不持有股票
        
        # 动态规划,计算每一天的状态
        for i in range(1, length):
            # 第 i 天持有股票的最大现金
            dp[i][0] = max(dp[i - 1][0], -prices[i])
            # 第 i 天不持有股票的最大现金
            dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
        
        # 最终结果是最后一天不持有股票时的最大现金
        return dp[-1][1]

力扣题目链接
题目文章讲解
题目视频讲解

二、力扣122. 买卖股票的最佳时机II

在这个问题中,我们需要找到一个策略,使得通过多次交易(买入和卖出股票)能够获得的最大利润。与之前只能进行一次交易的情况不同,这里允许在多个不同的时间点进行多次交易,每次交易只能持有一股股票。

我们仍然使用动态规划来解决这个问题。我们定义两个状态:

dp[i][0] 表示第 i 天持有股票时能够获得的最大现金金额。
dp[i][1] 表示第 i 天不持有股票时能够获得的最大现金金额。

与只能进行一次交易不同,这里第 i 天买入股票的现金金额可以是前一天不持有股票时的现金减去今天的股票价格,即 dp[i-1][1] - prices[i]。

持有股票时 (dp[i][0]):

如果第 i-1 天已经持有股票,那么保持现状:dp[i-1][0]。
如果第 i 天买入股票,那么所得现金为前一天不持有股票的现金减去今天的股票价格:dp[i-1][1] - prices[i]。
公式:dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])

不持有股票时 (dp[i][1]):

如果第 i-1 天已经不持有股票,那么保持现状:dp[i-1][1]。
如果第 i 天卖出股票,那么所得现金为今天的股票价格加上前一天持有股票的现金:dp[i-1][0] + prices[i]。
公式:dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i])

代码实现

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        length = len(prices)
        
        # 特殊情况处理
        if length == 0:
            return 0
        
        # 初始化 dp 数组,大小为 [length][2]
        # dp[i][0] 表示第 i 天持有股票时的最大现金
        # dp[i][1] 表示第 i 天不持有股票时的最大现金
        dp = [[0] * 2 for _ in range(length)]
        
        # 初始化第一天的状态
        dp[0][0] = -prices[0]  # 第 0 天买入股票
        dp[0][1] = 0  # 第 0 天不持有股票
        
        # 动态规划,计算每一天的状态
        for i in range(1, length):
            # 第 i 天持有股票的最大现金
            dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
            # 第 i 天不持有股票的最大现金
            dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i])
        
        # 最终结果是最后一天不持有股票时的最大现金
        return dp[-1][1]

力扣题目链接
题目文章讲解
题目视频讲解

二、力扣123. 买卖股票的最佳时机III

在这个问题中,我们需要找到一个策略,通过最多两次交易(即最多买入两次和卖出两次)来获得最大利润。每次交易只能持有一股股票,因此有五种状态:

dp[i][0]:表示第 i 天没有任何操作或不进行任何交易时的最大利润。
dp[i][1]:表示第 i 天进行了第一次买入操作后的最大利润。
dp[i][2]:表示第 i 天进行了第一次卖出操作后的最大利润。
dp[i][3]:表示第 i 天进行了第二次买入操作后的最大利润。
dp[i][4]:表示第 i 天进行了第二次卖出操作后的最大利润。

dp[i][1]: 第 i 天持有股票(第一次买入)的最大利润:
如果第 i 天买入股票:dp[i-1][0] - prices[i]。
如果第 i 天不买入股票:dp[i-1][1]。
公式:dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])

dp[i][2]: 第 i 天不持有股票(第一次卖出)的最大利润:
如果第 i 天卖出股票:dp[i-1][1] + prices[i]。
如果第 i 天不卖出股票:dp[i-1][2]。
公式:dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])

dp[i][3]: 第 i 天持有股票(第二次买入)的最大利润:
如果第 i 天买入股票:dp[i-1][2] - prices[i]。
如果第 i 天不买入股票:dp[i-1][3]。
公式:dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i])

dp[i][4]: 第 i 天不持有股票(第二次卖出)的最大利润:
如果第 i 天卖出股票:dp[i-1][3] + prices[i]。
如果第 i 天不卖出股票:dp[i-1][4]。
公式:dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i])

dp数组初始化

dp[0][0] = 0:表示第 0 天不进行任何操作,利润为 0。
dp[0][1] = -prices[0]:表示第 0 天第一次买入股票后的利润,即减去第 0 天的股票价格。
dp[0][2] = 0:表示第 0 天第一次卖出股票后的利润,因为不能卖出不存在的股票,所以利润为 0。
dp[0][3] = -prices[0]:表示第 0 天第二次买入股票后的利润,即再减去第 0 天的股票价格。
dp[0][4] = 0:表示第 0 天第二次卖出股票后的利润,同理也为 0。

代码实现

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        # 特殊情况处理,如果没有股票价格数据,返回 0
        if len(prices) == 0:
            return 0
        
        # 初始化 dp 数组,大小为 [len(prices)][5]
        dp = [[0] * 5 for _ in range(len(prices))]
        
        # 第 0 天的状态初始化
        dp[0][0] = 0  # 不操作
        dp[0][1] = -prices[0]  # 第一次买入
        dp[0][2] = 0  # 第一次卖出
        dp[0][3] = -prices[0]  # 第二次买入
        dp[0][4] = 0  # 第二次卖出
        
        # 动态规划,遍历每一天的状态
        for i in range(1, len(prices)):
            # 第 i 天不操作的状态,延续前一天的状态
            dp[i][0] = dp[i-1][0]
            # 第 i 天第一次买入股票的状态
            dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
            # 第 i 天第一次卖出股票的状态
            dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])
            # 第 i 天第二次买入股票的状态
            dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i])
            # 第 i 天第二次卖出股票的状态
            dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i])
        
        # 最终返回的结果是最后一天,第二次卖出股票后的最大利润
        return dp[-1][4]

力扣题目链接
题目文章讲解
题目视频讲解

举报

相关推荐

0 条评论