当前位置: 首页 > news >正文

代码随想录第32天:动态规划5(组合、排列、最小方法数)

一、零钱兑换(Leetcode 518)

1、确定dp数组以及下标的含义

使用 下标为[0, i]的coins[i]能够凑满j(包括j)这么大容量的包,有dp[i][j]种组合方法。

2、确定递推公式

dp[i][j] = dp[i - 1][j] + dp[i][j - nums[i]]

3. dp数组初始化

dp[i][0] 的含义:用物品i(即coins[i]) 装满容量为0的背包 有几种组合方法。

都有一种方法,即不装。dp[i][0] 都初始化为1

dp[0][j]的含义:用「物品0」(即coins[0]) 装满 背包容量为j的背包,有几种组合方法。如果 j 可以整除 物品0,那么装满背包就有1种组合方法。

4. 确定遍历顺序

二维DP数组的完全背包的两个for循环先后顺序都可以。

class Solution:def change(self, amount: int, coins: List[int]) -> int:n = len(coins)dp = [[0] * (amount + 1) for _ in range(n + 1)]dp[0][0] = 1  # 0个硬币凑出金额0的方法是1种for i in range(1, n + 1):  # 遍历硬币种类for j in range(amount + 1):  # 遍历目标金额# 不选当前硬币 coins[i-1]dp[i][j] = dp[i - 1][j]# 选当前硬币(只要j >= coins[i-1])if j >= coins[i - 1]:dp[i][j] += dp[i][j - coins[i - 1]]return dp[n][amount]

一维数组解法:

1、确定dp数组以及下标的含义

dp[j]:凑成总金额j的货币组合数为dp[j]

2、确定递推公式

dp[j] += dp[j - coins[i]]

3. dp数组初始化

装满背包容量为0 的方法是1,即不放任何物品,dp[0] = 1

4. 确定遍历顺序

先物品再背包求的是组合数,先背包后物品求的是排列数!!!

求组合所以本题先物品后背包

from typing import Listclass Solution:def change(self, amount: int, coins: List[int]) -> int:# 初始化一维数组 dp,长度为 amount + 1# dp[j] 表示凑出金额 j 的组合数dp = [0] * (amount + 1)# 凑出金额为 0 只有一种方式:什么也不选dp[0] = 1# 遍历每一个硬币for coin in coins:# 遍历金额从 coin 到 amount# 只从 coin 开始是因为凑不出比硬币面额更小的金额for j in range(coin, amount + 1):# 状态转移:凑出金额 j 的方法数 += 凑出金额 j - coin 的方法数dp[j] += dp[j - coin]# 返回凑出目标金额 amount 的组合方式数return dp[amount]

二、组合总合IV(Leetcode 377)

1、确定dp数组以及下标的含义

dp[i]:凑成目标正整数为i的排列个数为dp[i]

2、确定递推公式

dp[i] += dp[i - nums[j]]

3. dp数组初始化

dp[0] = 1

4. 确定遍历顺序

先物品再背包求的是组合数,先背包后物品求的是排列数!!!

求排列所以本题先背包后物品

from typing import Listclass Solution:def combinationSum4(self, nums: List[int], target: int) -> int:# dp[i] 表示凑出和为 i 的排列个数(顺序不同算不同的组合)dp = [0] * (target + 1)# 凑出和为 0 只有一种方式:什么也不选dp[0] = 1# 从 1 到 target 遍历每一个目标值 ifor i in range(1, target + 1):# 遍历每一个数字 num,尝试使用它来构造 ifor j in range(len(nums)):if i >= nums[j]:# 如果当前目标值 i ≥ num,则可以从 i - num 的方案转移过来dp[i] += dp[i - nums[j]]# 最终结果是凑出目标和 target 的所有排列数return dp[target]

三、爬楼梯(Kamacoder 57)

1、确定dp数组以及下标的含义

dp[i]:爬到有i个台阶的楼顶,有dp[i]种方法。

2、确定递推公式

dp[i]有几种来源,dp[i - 1],dp[i - 2],dp[i - 3] 等等,即:dp[i - j],递推公式为:dp[i] += dp[i - j]

3. dp数组初始化

dp[0] = 1

4. 确定遍历顺序

先物品再背包求的是组合数,先背包后物品求的是排列数!!!

求排列所以本题先背包后物品

def solve(n, m):dp = [0] * (n + 1)dp[0] = 1for j in range(1, n + 1):for i in range(1, m + 1):if j >= i:dp[j] += dp[j - i]return dp[n]if __name__ == '__main__':n, m = list(map(int, input().split(' ')))print(solve(n, m))

四、零钱兑换(Leetcode 322)

1、确定dp数组以及下标的含义

dp[j]:凑足总额为j所需钱币的最少个数为dp[j]

2、确定递推公式

凑足总额为 j - coins[i] 的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j]

所以dp[j] 要取所有 dp[j - coins[i]] + 1 中最小的。

递推公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);

3. dp数组初始化

dp[0] = 0

dp[j]应该初始化为一个最大的数float('inf'),这样在min(dp[j - coins[i]] + 1, dp[j])比较的过程中保持更新

所以下标非0的元素都初始化为最大值float('inf')。

4. 确定遍历顺序

先物品再背包求的是组合数,先背包后物品求的是排列数!!!

本题并不强调集合是组合还是排列,习惯先物品后背包

from typing import Listclass Solution:def coinChange(self, coins: List[int], amount: int) -> int:# 初始化 dp 数组,长度为 amount + 1,初始值为正无穷(代表初始无法到达)# dp[i] 表示凑出金额 i 所需的最少硬币数dp = [float('inf')] * (amount + 1)# 凑出金额 0 所需的硬币数为 0dp[0] = 0# 遍历每一种硬币for coin in coins:# 对每一个从 coin 到 amount 的金额 j 进行遍历for j in range(coin, amount + 1):# 状态转移方程:如果 j - coin 可以被凑出# 则 j 也可以被凑出,其所需硬币数为 dp[j - coin] + 1dp[j] = min(dp[j], dp[j - coin] + 1)# 如果最终凑不出 amount 金额,返回 -1;否则返回最小硬币数return dp[amount] if dp[amount] != float('inf') else -1
http://www.xdnf.cn/news/288847.html

相关文章:

  • 二、Python变量基础(2)
  • STM32 PulseSensor心跳传感器驱动代码
  • 常用非对称加密算法的Python实现及详解
  • simulink使能子系统的四种配置
  • uniapp开发06-视频组件video的使用注意事项
  • 大数据分析在视频监视方面的应用综述
  • ROS2 开发踩坑记录(持续更新...)
  • Serverless
  • 机器学习项目流程极简入门:从数据到部署的完整指南
  • 物联网mqtt和互联网http协议区别
  • 硬件工程师面试常见问题(14)
  • [学习] RTKlib详解:功能、工具与源码结构解析
  • 基于MATLAB的图像色彩识别项目,彩色图像矩阵识别
  • 大模型推理--从零搭建大模型推理服务器:硬件选购、Ubuntu双系统安装与环境配置
  • Python实战:基于控制台与MySQL的电影票预订系统开发指南
  • 学习路线(机器人系统)
  • 模糊控制理论(含仿真)
  • 7400MB/s5050TBW完美结合,全新希捷酷玩530R SSD体验评测
  • 10 种最新的思维链(Chain-of-Thought, CoT)增强方法
  • 攻防世界-php伪协议和文件包含
  • 第一章-Rust入门
  • 音频感知动画新纪元:Sonic让你的作品更生动
  • PE文件结构(导出表)
  • 专家系统的推理流程深度解析
  • Java SE(8)——继承
  • 虚拟dom是什么,他有什么好处
  • 深度学习里程碑:AlexNet 架构解析与核心技术详解
  • 【深度学习|学习笔记】Deep Belief Network(DBN,深度置信网络)起源、原理、发展和应用(附代码)
  • 【KWDB 创作者计划】基于 ESP32 + KWDB 的智能环境监测系统实战
  • 高可用架构设计——故障响应