AI 刷题 272.最大化糖果美味值问题 | 豆包MarsCode AI刷题

45 阅读3分钟

问题描述

小C面临一个选择问题:她可以从编号为1到n的糖果中任意选择一些糖果作为奖励,但需要遵守一个限制规则:如果选择了编号为i的糖果,那么编号为i-1、i-2、i+1、i+2的糖果将不能被选择。每个糖果都有一个对应的美味值,小C希望所选糖果的美味值之和最大。

例如:当有7个糖果,编号为1到7,美味值分别为 3, 1, 2, 7, 10, 2, 4,小C可以选择编号为1、4、7的糖果,这样可以得到最大美味值之和为 3 + 7 + 4 = 14


测试样例

样例1:

输入:n = 7, a = [3, 1, 2, 7, 10, 2, 4]
输出:14

样例2:

输入:n = 5, a = [1, 10, 2, 5, 8]
输出:18

样例3:

输入:n = 6, a = [4, 5, 6, 1, 2, 3]
输出:9


分析

算法步骤

  1. 定义状态

    • 使用一个数组 dp,其中 dp[i] 表示在前 i 个糖果中可以获得的最大美味值。
  2. 状态转移方程

    • 对于每个糖果 i,我们有两种选择:

      • 选择第 i 个糖果,那么我们不能选择 i-1i-2 的糖果,因此 dp[i] = a[i] + dp[i-3]
      • 不选择第 i 个糖果,那么 dp[i] = dp[i-1]
    • 因此,状态转移方程为:

dp[i] = max(dp[i-1], a[i] + dp[i-3])
  1. 初始化

    • 我们需要初始化前几个状态,因为状态转移方程依赖于 dp[i-3]

      • dp[0] = a[0]
      • dp[1] = max(a[0], a[1])
      • dp[2] = max(a[0], a[1], a[2])
  2. 填充dp数组

    • 使用循环从 i=3 开始,直到 n-1,填充 dp 数组。
  3. 返回结果

    • 最终结果存储在 dp 数组的最后一个位置,即 dp[n-1]

难点分析

  1. 状态转移方程的理解

    • 理解为什么选择第 i 个糖果时,不能选择 i-1i-2 的糖果,并且需要加上 dp[i-3] 的美味值。
    • 理解为什么不选择第 i 个糖果时,直接继承 dp[i-1] 的值。
  2. 初始化的正确性

    • 确保前几个状态的初始化正确,因为状态转移方程依赖于这些初始值。
  3. 边界条件的处理

    • 处理 n 为 0、1、2 的特殊情况,因为这些情况下状态转移方程不适用。
  4. 动态规划数组的填充

    • 确保在填充 dp 数组时,正确地应用状态转移方程,避免遗漏或错误的状态更新。

代码

def solution(n: int, a: list) -> int:
    if n == 0:
        return 0
    if n == 1:
        return a[0]
    if n == 2:
        return max(a[0], a[1])
    
    # 初始化dp数组
    dp = [0] * n
    dp[0] = a[0]
    dp[1] = max(a[0], a[1])
    dp[2] = max(a[0], a[1], a[2])
    
    # 填充dp数组
    for i in range(3, n):
        dp[i] = max(dp[i-1], a[i] + dp[i-3])
    
    return dp[-1]

if __name__ == '__main__':
    print(solution(7, [3, 1, 2, 7, 10, 2, 4]) == 14)
    print(solution(5, [1, 10, 2, 5, 8]) == 18)
    print(solution(6, [4, 5, 6, 1, 2, 3]) == 9)

代码分析

  • 边界条件处理

    • 代码处理了 n 为 0、1、2 的特殊情况。
    • n == 0 时,返回 0。
    • n == 1 时,返回 a[0]
    • n == 2 时,返回 max(a[0], a[1])
  • 初始化

    • 代码初始化了 dp 数组的前几个值:

      • dp[0] = a[0]
      • dp[1] = max(a[0], a[1])
      • dp[2] = max(a[0], a[1], a[2])
  • 状态转移方程

    • 代码使用了状态转移方程:
dp[i] = max(dp[i-1], a[i] + dp[i-3])
-   这表示在每个位置 `i`,我们选择当前糖果 `a[i]` 并加上 `dp[i-3]` 的美味值,或者不选择当前糖果,继承 `dp[i-1]` 的值。
  • 填充dp数组

    • 代码使用循环从 i=3 开始,直到 n-1,正确填充了 dp 数组。
  • 返回结果

    • 代码返回 dp 数组的最后一个值 dp[-1],即在前 n 个糖果中可以获得的最大美味值。