青训营X豆包MarsCode 技术训练营刷题技巧(动态规划专题篇七)| 豆包MarsCode AI 刷题

89 阅读2分钟

最大化数组和的问题

题目描述

image.png

题目分析

本题是简单的线性动态规划问题,类似数据分割问题,但本题需要操作所有数组元素。

动态规划状态分析

  • 状态定义

    • dp[i]表示考虑到第i个元素后,数组可以达到的最大和。
  • 状态转移方程

       dp[i]=max(dp[i−1]+A[i]×2,dp[i−1]+A[i]÷2)
    
    • 这里:

      • dp[i−1]+A[i]×2:表示选择将A[i]翻倍。
      • dp[i−1]+A[i]÷2:表示选择将A[i]减半。
  • 边界条件

    • dp[0]=max(A[0]×2,A[0]÷2)

      • 第一个元素的操作只有翻倍和减半两种。
  • 目标

    • 最终的结果是dp[N−1],即考虑所有元素后的最大和。

Python代码

def solution(N: int, A: list) -> int:
    # 初始化 dp 数组
    dp = [0] * N
    
    # 初始化第一个元素的选择
    dp[0] = max(A[0] * 2, A[0] // 2)
    
    # 逐步计算每个元素的最优选择
    for i in range(1, N):
        double = A[i] * 2  # 翻倍操作
        halve = A[i] // 2  # 减半操作
        
        dp[i] = max(dp[i-1] + double, dp[i-1] + halve)
    
    # 返回最后的最大和
    return dp[N-1]

# 测试用例
if __name__ == '__main__':
    print(solution(N=3, A=[-4, 2, 4]) == 10)  # 示例 1
    print(solution(N=2, A=[-8, 4]) == 4)     # 示例 2
    print(solution(N=4, A=[-6, 6, 2, -2]) == 12)  # 示例 3

最优硬币组合问题

题目描述

image.png

题目分析

这道题属于完全背包问题的变体,

动态规划状态描述

1. 状态定义
  • 定义 dp[i] 为「金额为 i 时,最少的硬币数量」。
  • 如果无法组成金额 i,则设定 dp[i]=∞
2. 状态转移方程
  • 若选择硬币 array[j]: dp[i]=min⁡(dp[i],dp[i−array[j]]+1)

    • 意思是:组成金额i的最少硬币数量,要么不选当前硬币,保留之前的最优解 dp[i];要么选择当前硬币 array[j],通过减去硬币值递归寻找子问题 dp[i−array[j]]
3. 边界条件
  • dp[0]=0:组成金额为 0 时,所需硬币数为 0。
  • dp[i]=∞(初始化):表示金额i无法被硬币数组组成。
4. 目标
  • 通过 dp[total]得到金额total的最少硬币数。
  • dp[total]=∞,则表示无法组成目标金额,返回 None

Python代码

def solution(array, total):
    array.sort()
    dp = [float('inf')] * (total + 1)
    dp[0] = 0

    # 动态规划来求出最少的元素数
    for num in array:
        for i in range(num, total + 1):
            if dp[i - num] != float('inf'):
                dp[i] = min(dp[i], dp[i - num] + 1)

    # 如果无法组合成total,返回 None
    if dp[total] == float('inf'):
        return None

    # 逆向查找组成 total 的具体元素
    result = []
    remaining_total = total
    for i in range(len(array) - 1, -1, -1):
        while remaining_total >= array[i] and dp[remaining_total] == dp[remaining_total - array[i]] + 1:
            result.append(array[i])
            remaining_total -= array[i]

    return result

if __name__ == "__main__":
    # 测试用例
    print(solution([1, 2, 3, 10], 21) == [10, 10, 1])  # 输出: True
    print(solution([1, 2, 5], 18) == [5, 5, 5, 2, 1])  # 输出: True