编程实现背包的递归和非递归两种解法_算法动态规划(七)背包问题4
⚠️今天继续我们来探讨背包问题中的完全背包问题。完全背包:N个物品,容量为V,每个物品可以无限次使用,求达到V的最值。
???今日练习(一)零钱兑换(LeetCode-322)。给定一批硬币coins数组,每个硬币可以不限次数使用,求凑成总金额V至少需要多少个硬币。找不到输出-1。举例:
输入:[1,2,5] , 11输出:3。1+5+5=11输入:[2],3输出:-1;
?解法一:记忆化递归
?思路:
总体思路就是用coins中的每个数去凑总金额amount,用总金额减去使用过的数,直到amount小等于0退出递归。当amount==0,说明刚刚好凑齐。退出递归。使用一个map来保存递归中产生的零钱值,减少重复递归。
Mapmap = new HashMap<>(); public int coinChange(int[] coins, int amount) { if(amount <= 0){ return 0; } return find_h(coins,amount); } private int find_h(int[] nums,int amount){ if(amount <0){ return -1; } if(amount == 0){ return 0; } if(map.containsKey(amount)){ return map.get(amount); } int count=Integer.MAX_VALUE; for(int num:nums){ if(num > amount){ continue; } int solu=find_h(nums,amount-num); if(solu>=0){ count = Math.min(count,solu+1); } } if(count == Integer.MAX_VALUE){ count =-1; } map.put(amount,count); return map.get(amount); }
?解法二:动态规划【自上而下】
?思路:
状态定义:F(S),凑齐总金额S,需要的最小硬币数。
状态转移方程:F(S) = F(S-coins[i]) + 1。
public int coinChange(int[] coins, int amount) { if (amount < 1) return 0; return coinChange_h(coins, amount,new int[amount+1]);}private int coinChange_h(int[] coins, int amount,int[] count) { if (amount < 0) return -1; if (amount == 0) return 0; if (count[amount] != 0) return count[amount]; int min = Integer.MAX_VALUE; for (int coin : coins) { int res = coinChange_h(coins, amount - coin,count); if (res >= 0 ) min = Math.min(1 + res,min); } count[amount] = min == Integer.MAX_VALUE ? -1:min; return count[amount];}
?解法三:动态规划【自下而上】
?思路:
状态定义:dp[j],凑齐总金额j,需要的最小硬币数。
状态转移方程:dp[i][j]= min(dp[i][j],dp[i](j-coins[i]) + 1)。凑齐总金额j需要的最小硬币数,当地i个硬币选或者不选两种情况。
public int coinChange_2(int[] coins, int amount) { if (amount < 1) return 0; int[] dp = new int[amount+1]; Arrays.fill(dp,amount+1); //这儿解释下为啥默认填充amount+1,凑齐amount最多也就是面值为1的数总计用amount个, // 所以最少个数一定是 dp[0]=0; for(int j=1;j<=amount;j++){ for(int num:coins){ if(num <= j){ dp[j]=Math.min(dp[j],dp[j-num]+1); } } } return dp[amount]==amount+1?-1:dp[amount];}
复杂度分析
时间复杂度:O(SN):这里S是总金额,N是提供的不同面额数,即数组长度。我们要计算O(S)个不同总金额,对每次的总金额需要N个面额来转移状态,一共需要O(SN)的时间复杂度。
空间复杂度:O(S),我们使用了一个S+1的dp数组。
不积跬步,无以至千里。
文章有帮助的话,点个转发
、在看呗。
谢谢支持哟 (*^__^*)
END
?
编程实现背包的递归和非递归两种解法_算法动态规划(七)背包问题4相关推荐
- C#实现(递归和非递归)快速排序和简单排序
C#实现(递归和非递归)快速排序和简单排序 本人因为最近工作用到了一些排序算法,就把几个简单的排序算法,想冒泡排序,选择排序,插入排序,奇偶排序和快速排序等整理了出来,代码用C#代码实现,并且通过了测 ...
- 二叉树创建及遍历算法(递归及非递归)(转)
//二叉树处理头文件 //包括二叉树的结构定义,二叉树的创建,遍历算法(递归及非递归), /* 作者:成晓旭 时间:2001年10月7日(18:49:38-20:00:00) 内容:完成二叉树创建,二 ...
- 【恋上数据结构】递归(函数调用过程、斐波那契数列、上楼梯、汉诺塔、递归转非递归、尾调用)
递归(Recursion) 什么是递归? 函数的调用过程(栈空间) 函数的递归调用过程 递归实例分析(1 + 2 + 3 + ... + 100 的和) 递归的基本思想.使用套路 斐波那契数列 fib ...
- 二叉树的先中后序递归和非递归遍历(数据结构作业)
一.设计思想 我创建二叉树是用的先序创建,其中用'#'代表空节点. 1.递归先序遍历 (1)如果当前节点为空节点(用'#'代表空节点),结束当前函数 (2)打印当前节点 (2)递归当前节点的左子树 ( ...
- C++实现二叉树 前、中、后序遍历(递归与非递归)非递归实现过程最简洁版本
本文并非我所写,是复制的该链接中的内容: 最近学习二叉树,想编程实现递归和非递归的实现方式: 递归的方式就不说了,因为大家的递归程序都一样:但是对于非递归的实现方式, 根据这几天的查阅资料已看到差不多 ...
- C++第七次作业(函数_递归与非递归_多文件)
文章目录: 一:C++递归与非递归实现整数的阶乘 代码实现 运行结果 二:C++递归与非递归实现Fibonacci数列的计算:a0=1; a1=1; a2=a0+a1; a3=a1+a2; ..... ...
- python创建树结构、求深度_数据结构-树以及深度、广度优先遍历(递归和非递归,python实现)...
前面我们介绍了队列.堆栈.链表,你亲自动手实践了吗?今天我们来到了树的部分,树在数据结构中是非常重要的一部分,树的应用有很多很多,树的种类也有很多很多,今天我们就先来创建一个普通的树.其他各种各样的树 ...
- 二叉树的几种递归和非递归式遍历:
二叉树的几种递归和非递归式遍历: 1 #include <fstream> 2 #include <iostream> 3 4 using namespace std; 5 6 ...
- 全排列(含递归和非递归的解法)
全排列在近几年各大网络公司的笔试中出现的比较频繁 首先来看看题目是如何要求的(百度迅雷校招笔试题). 用C++写一个函数, 如 Foo(const char *str), 打印出 str 的全排列, ...
最新文章
- 通过示例学习JavaScript闭包
- 基于ssh的ktv预定管理系统
- 写了一个开源的ASP.Net的系统信息探针(适用于MS.Net 1.x/2.0和Mono 1.0/2.0)
- python基础教程:两个list之间移动元素
- client-go workqueue demo
- Redhat Mongodb学习笔记
- 企业分布式微服务云SpringCloud SpringBoot mybatis (八)消息总线(Spring Cloud Bus)
- 北京网信金服PHP薪资_【企航金服工资|企航金服待遇怎么样】-看准网
- 心语家园系统维护工具箱v1.0
- kali 邮箱攻击_利用Kali linux制作钓鱼网站
- Java工作流引擎学习----JBPM(一)
- 如何通过vin及发动机号查询车辆出险、理赔、事故记录
- dwg格式转换成jpg图片
- ARCMAP里面关于地理投影方面的知识
- 阿里云ACP云计算对象存储OSS例题
- java orm全称_[Java-基础] 什么是ORM
- mysql 编程算法_十大编程算法助程序员走上高手之路
- Python老司机带你快速搞定日志分析工具
- Android 加壳与脱壳方式总结
- vue学习之关于element日历calendar组件中上月,今天,下月的显示