算法训练 | 动态规划Part5 | 518.零钱兑换 II、377.组合总和 Ⅳ 、70.爬楼梯 (进阶)

本文主要是介绍算法训练 | 动态规划Part5 | 518.零钱兑换 II、377.组合总和 Ⅳ 、70.爬楼梯 (进阶),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

518. 零钱兑换 II

动态规划法

377. 组合总和 Ⅳ

动态规划法

70. 爬楼梯 (进阶)

动态规划法


518. 零钱兑换 II

  • 题目链接:518. 零钱兑换 II - 力扣(LeetCode)

  • 文章讲解:代码随想录

动态规划法
  • 完全背包:01背包内嵌的循环是从大到小遍历,为了保证每个物品仅被添加一次。而完全背包的物品是可以添加多次的,所以要从小到大去遍历

  • 解题思路

      但本题和纯完全背包不一样,纯完全背包是凑成背包最大价值是多少,而本题是要求凑成总金额的物品组合个数!注意题目描述中是凑成总金额的硬币组合数,组合不强调元素之间的顺序,排列强调元素之间的顺序。

  • 解题步骤

    • 确定dp数组以及下标的含义:dp[j]凑成总金额j的货币组合数为dp[j]

    • dp[j] 就是所有的dp[j - coins[i]](考虑coins[i]的情况)相加。所以递推公式:dp[j] += dp[j - coins[i]];

    • dp数组如何初始化:首先dp[0]一定要为1,dp[0] = 1是 递归公式的基础。如果dp[0] = 0 的话,后面所有推导出来的值都是0了。

    • 确定遍历顺序:本题中我们是外层for循环遍历物品(钱币),内层for遍历背包(金钱总额)。这种遍历顺序中dp[j]里计算的是组合数。如果把两个for交换顺序,此时dp[j]里算出来的就是排列数。

    • 举例推导dp数组:

  • 代码一:动态规划

// 时间复杂度: O(mn),其中 m 是amount,n 是 coins 的长度
// 空间复杂度: O(m)
class Solution {
public:int change(int amount, vector<int>& coins) {vector<int> dp(amount + 1, 0);dp[0] = 1;for (int i = 0; i < coins.size(); i++) { // 遍历物品for (int j = coins[i]; j <= amount; j++) { // 遍历背包dp[j] += dp[j - coins[i]];}}return dp[amount];}
};

377. 组合总和 Ⅳ

  • 题目链接:377. 组合总和 Ⅳ - 力扣(LeetCode)

  • 文章讲解:代码随想录

动态规划法
  • 解题思路

    • 本题题目描述说是求组合,但又说是可以元素相同顺序不同的组合算两个组合,其实就是求排列!

  • 解题步骤

    • 确定dp数组以及下标的含义:dp[i]: 凑成目标正整数为i的排列个数为dp[i]

    • 确定递推公式:dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j]) 推导出来。因为只要得到nums[j],排列个数dp[i - nums[j]],就是dp[i]的一部分。求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];

    • 个数可以不限使用,说明这是一个完全背包。得到的集合是排列,说明需要考虑元素之间的顺序。所以本题遍历顺序最终遍历顺序:target(背包)放在外循环,将nums(物品)放在内循环,内循环从前到后遍历。

    • 举例来推导dp数组:

  • 代码一:动态规划

// 时间复杂度: O(target * n),其中 n 为 nums 的长度
// 空间复杂度: O(target)
class Solution {
public:int combinationSum4(vector<int>& nums, int target) {vector<int> dp(target + 1, 0);dp[0] = 1;for (int i = 0; i <= target; i++) { // 遍历背包for (int j = 0; j < nums.size(); j++) { // 遍历物品if (i - nums[j] >= 0 && dp[i] < INT_MAX - dp[i - nums[j]]) {dp[i] += dp[i - nums[j]];}}}return dp[target];}
};

70. 爬楼梯 (进阶)

  • 题目链接:57. 爬楼梯(第八期模拟笔试)

  • 文章讲解:代码随想录

动态规划法
  • 解题思路

      一步一个台阶,两个台阶,三个台阶,.......,直到 m个台阶。问有多少种不同的方法可以爬到楼顶呢?这又有难度了,这其实是一个完全背包问题。1阶,2阶,.... m阶就是物品,楼顶就是背包。每一阶可以重复使用,例如跳了1阶,还可以继续跳1阶。问跳到楼顶有几种方法其实就是问装满背包有几种方法。

  • 解题步骤

    • 确定dp数组以及下标的含义:dp[i]:爬到有i个台阶的楼顶,有dp[i]种方法。

    • dp数组如何初始化:既然递归公式是 dp[i] += dp[i - j],那么dp[0] 一定为1,dp[0]是递归中一切数值的基础所在,如果dp[0]是0的话,其他数值都是0了。下标非0的dp[i]初始化为0,因为dp[i]是靠dp[i-j]累计上来的,dp[i]本身为0这样才不会影响结果。

    • 确定遍历顺序:这是背包里求排列问题,即:1、2 步 和 2、1 步都是上三个台阶,但是这两种方法不一样!所以需将target放在外循环,将nums放在内循环。每一步可以走多次,这是完全背包,内循环需要从前向后遍历。

  • 代码一:动态规划

// 时间复杂度: O(n * m)
// 空间复杂度: O(n)
#include <iostream>
#include <vector>
using namespace std;
int main() {int n, m;while (cin >> n >> m) {vector<int> dp(n + 1, 0);dp[0] = 1;for (int i = 1; i <= n; i++) { // 遍历背包for (int j = 1; j <= m; j++) { // 遍历物品if (i - j >= 0) dp[i] += dp[i - j];}}cout << dp[n] << endl;}
}

这篇关于算法训练 | 动态规划Part5 | 518.零钱兑换 II、377.组合总和 Ⅳ 、70.爬楼梯 (进阶)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1075786

相关文章

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

.NET利用C#字节流动态操作Excel文件

《.NET利用C#字节流动态操作Excel文件》在.NET开发中,通过字节流动态操作Excel文件提供了一种高效且灵活的方式处理数据,本文将演示如何在.NET平台使用C#通过字节流创建,读取,编辑及保... 目录用C#创建并保存Excel工作簿为字节流用C#通过字节流直接读取Excel文件数据用C#通过字节

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第