完全背包问题Leecode322零钱兑换和Leecode518零钱兑换||
文章目录
- Leecode 322零钱兑换
- Leecode 518零钱兑换II
Leecode 322零钱兑换
题目大意
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。你可以认为每种硬币的数量是无限的。
题解思路
状态确定:dp[i]表示凑成面值i所需要的最小硬币数。从0开始遍历一直到amount,求出dp[amount]即为所求解。
状态方程:
dp[i]=min(dp[i-coins[j],dp[i]),i>=coins[i]
技巧:初始时给所有的dp[i]赋值为amount+1,最多硬币数是小于这个值的,如果遍历到amount,其值dp[amount]仍为amount+1,说明没有任何一种硬币组合数使其面值等于amount,则返回-1;在这个初始赋值为最大值时,所有
边界确定:dp[0]=0;
参考代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int coinChange(int* coins, int coinsSize, int amount){int dp[amount+1];
for(int i=0;i<=amount;i++){dp[i]=amount+1;//便于后序检测是否有面值无法用该硬币组合数构成
}
dp[0]=0;
for(int i=1;i<=amount;i++){for(int j=0;j<coinsSize;j++){if(i>=coins[j])//如果当前待求面值大于或等于该硬币的值,即一定不能选该枚硬币,否则可选dp[i]=min(dp[i],dp[i-coins[j]]+1);}
}if(dp[amount]>amount)return -1;
else return dp[amount];
}
int main(){int n;int coins[12],amount;cin>>n;for(int i=0;i<n;i++){cin>>coins[i];}cin>>amount;cout<<coinChange(coins,n,amount); return 0;
}
题目复盘
刚开始看到这道题目时就模仿着之前做的题目往二维套,写了下面这个思虑不周的错误代码
// int dp[13][10001]={0};
// for(int j=1;j<=amount;j++)
// dp[0][j]=-1;
// dp[1][1]=1;
// for(int i=1;i<=coinsSize;i++){// for(int j=0;j<=amount;j++)
// if(j<coins[i-1]&&dp[i-1][j]!=-1)
// dp[i][j]=dp[i-1][j];
// else if(dp[i-1][j]==-1)
// dp[i][j]=-1;
// else if(coins[i-1]<j)
// dp[i][j]=min(dp[i-1][j],dp[i-1][j-coins[i-1]]+1);
// }
// return dp[coinsSize+1][amount];
该代码错误如下:
向之前那样一次遍历前i个硬币,这种默认硬币是只能使用一次,实际每个硬币可使用多次
之后看了题解用一位数组存储状态,因为初值赋的不合理,使后面思路凌乱,又写了以下错误代码:
//一维动态规划
// int dp[10000]={0};
// //for(int i=0;i<coinsSize;i++) dp[coins[i]]=1;
// for(int i=1;i<=amount;i++)
// {//
// int mi=10000;
// for(int j=0;j<coinsSize;j++)
// {// if(i==coins[j]){// dp[i]=1;
// break;
// }
// if(i>coins[j])
// dp[i]=fmin(dp[i-coins[j]]+1,dp[i]);
else if(i<coins[j])
dp[i]=fmin(dp[i],dp[i]);
// }
//
// if(mi=-1)
// dp[i]=-1;
// else
// dp[i]=mi+1;
// }
// return dp[amount];
希望下次做题时逻辑能更清晰一些,想的更明白一些,灵活运用动态规划这个思想!
Leecode 518零钱兑换II
题意
给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带符号整数。
解题思路
为了避免金币种类因顺序不同遍历导致的重复,此解题在外层先遍历金币的种类数,在内层遍历构成的金额数。这样构成每一金额的硬币都是按顺序排好的即可避免重复。用dp[i]存放使用前面几种类硬币构成的金额i的方案个数,在遍历到本层时再用dp[i]=dp[i]+dp[i-coins[j]]更新到达本层时构成金额i的种类数。
状态表示:dp[i]凑成金额i的组合数
状态转换: dp[i]=dp[i]+dp[i-coins[j]],i>=coins[j]
源码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int coinChange(int* coins, int coinsSize, int amount){//int dp[amount+1]={0};for(int i=0;i<=amount;i++)dp[i]=0;
// for(int i=0;i<=amount;i++)
// dp[i]=amount+1; //给dp[i] 赋初值为一个不可能达到的值,如果最后真的等于这个值说明dp[i]不可能实现 dp[0]=1;
// for(int i=1;i<=amount;i++){// for(int j=0;j<coinsSize;j++)//遍历可用的每一个硬币,看是否能使用
// if(i>=coins[j])
// dp[i]+=dp[i-coins[j]];
// }for(int i=0;i<coinsSize;i++){//遍历可用的每一个硬币,看是否能使用for(int j=0;j<=amount;j++)if(j>=coins[i])dp[j]+=dp[j-coins[i]];}return dp[amount];
}
int main(){int n;int coins[12],amount;cin>>n;for(int i=0;i<n;i++){cin>>coins[i];}cin>>amount;cout<<coinChange(coins,n,amount); return 0;
}
复盘
刚开始认为这道题与322除了dp[i]含义不同与状态方程不同没什么区别,直到手动运行上述注释的错误代码后发现那种写法有重复的方案。如coins[1 2 5],amount=5;在刚开始写的时候方案:“1 2 2”和方案“ 2 2 1”是都被记入到dp[i]中的,导致了很多重复。真佩服那种第一次就能想到避免重复的方法的人!
完全背包问题Leecode322零钱兑换和Leecode518零钱兑换||相关推荐
- 深入解析之将100元兑换为1元、5元、10元的零钱,请问有多少种兑换方法
要将100元兑换为1元.5元.10元的零钱,请问有多少种兑换方法?这道算法题不知不觉走进了我的世界,引起了我极大的兴趣.现在就将我对它的研究分享出来,供大家点评. 看到这个题目的第一感觉就是一个三元一 ...
- 将100元兑换为1元、5元、10元的零钱,请问有多少种兑换方法?
public static void main(String[] args) {//将100元兑换为1元.5元.10元的零钱,请问有多少种兑换方法?//i为一元数量,j为五元数量,k为十元数量int ...
- 【必备算法】动态规划:LeetCode题(六)322. 零钱兑换,518. 零钱兑换 II
322. 零钱兑换² 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总金额,返回 -1. 示例 1: ...
- python换零钱_Python算法之零钱兑换问题的解法
比如:顾客购物买37元东西,给了100元,要找63元,那最少数量就是1张50元,1张10元,3张1元,一共4张. 方法一: 贪心策略 解决这个问题,最直观的就是使用贪心策略.我们会从最大面值的钱开始, ...
- python找零钱_Python递归 - 找零钱
特殊的方法-循环: #无法解决某些情况,例如存在21元的零钱 def fun(n): count = 0 while n > 25: n = n - 25 count = count + 1 w ...
- cms小猪o2o企业付款配置中微信提现配置实现商家转账到零钱(企业付款到零钱)解决:“操作失败!产品权限验证失败,请查看您当前是否具有该产品的权限“的错误提示
先说下概念什么是商家转账到零钱?其实这个功能是由企业付款到零钱功能演变过来的,微信支付里面在2022年5月之前这个功能一直叫"企业付款到零钱"后来因为业务需求改成了"商家 ...
- php企业微信付款到零钱,企业付款到零钱功能介绍及常见问题
Q:为什么我在[产品中心]找不到[企业付款到零钱]产品? A:需同时满足三个条件,才能看到开通入口: 1)入驻满足90天: 2)截止今日往回推30天有连续不间断的交易: 3)交易需为正常的健康交易. ...
- 凑零钱问题_凑零钱的组合
给定K种面值c1,c2,....ck,每种金币数量,例举总和为amount的,至少需要的金币的组合 关于计算金币数量有解法,金币组合方式可以参考,暴力解,从小到大,找到即是最小组合 import ja ...
- html网页代码实现找零钱,算法训练 找零钱
资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 有n个人正在饭堂排队买海北鸡饭.每份海北鸡饭要25元.奇怪的是,每个人手里只有一张钞票(每张钞票的面值为25.50.100元),而 ...
最新文章
- Spring_boot_pom.xml和启动方式
- 无法连接NVIDIA驱动:NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver
- [leetcode] 数字游戏
- jquery自动补全
- c语言#include后的尖括号和双引号有什么区别?
- php服务器队列执行,lnmp php添加队列服务器的配置
- Yii 框架里数据库操作详解-[增加、查询、更新、删除的方法](转)
- js 浅拷贝直接赋值_JS中的赋值、浅拷贝与深拷贝
- 一种真正意义上的Session劫持
- 诺基亚首款5G手机正式发布!还有Nokia 5310经典再现
- Linux查看文件内容的6种命令
- Bluno 是干什么的?- 云物联戒烟设备的可选原型之一
- Python小程序(3)--BMR(基础代谢率)计算器
- 10种软件开发模型整理
- windows10一键修改开机动画
- 哔哩哔哩视频下载助手
- netty 高匿ip检测_检测代理IP匿名程度的方法
- elipse配色方案
- Python课程总结
- 计算机系统引导失败怎么办,win7系统引导选择失败怎么办|win7系统引导选择失败的解决方法...