换钱的最少货币数

【题目】
给定数组arr,arr中所有的值都为正数且不重复。
每个值代表一种面值的货币,每种面值的货币可以使用任意张,
再给定一个整数aim代表要找的钱数,求组成aim的最少货币数。

【举例】
arr=[5,2,3],aim=20。
4张5元可以组成20元,其他的找钱方案都要使用更多张的货币,所以返回4。
arr=[5,2,3],aim=0。不用任何货币就可以组成0元,返回0。
arr=[3,5],aim=2。根本无法组成2元,钱不能找开的情况下默认返回-1。

【解答】
原问题的经典动态规划方法。如果arr的长度为N,
生成行数为N、列数为aim+1的动态规划表的dp。
dp[i][j]的含义是,在可以任意使用arr[0..i]货币的情况下,
组成j所需的最小张数。根据这个定义,dp[i][j]的值按如下方式计算:
1.dp[0..N-1][0]的值(即dp矩阵中第一列的值)表示找的钱数为0时需要的最少张数,
钱数为0时,完全不需要任何货币,所以全设为0即可。
2.dp[0][0..aim]的值(即dp矩阵中第一行的值)表示只能使用arr[0]货币的情况下,
找某个钱数的最小张数。比如,arr[0]=2,那么能找开的钱数为2,4,6,8,...
所以令dp[0][2]=1,dp[0][4]=2,dp[0][6]=3,...第一行其他位置所代表的钱数一律找不开,
所以一律设为32位整数的最大值,我们把这个值记为max。
3.剩下的位置依次从左到右,再从上到下计算。
假设计算到位置(i ,j),dp[i][j]的值可能来自下面的情况。

● 完全不使用当前货币arr[i]情况下的最少张数,即dp[i-1][j]的值。
● 只使用1张当前货币arr[i]情况下的最少张数,即dp[i-1][j-arr[i]]+1。
● 只使用2张当前货币arr[i]情况下的最少张数,即dp[i-1][j-2*arr[i]]+2。
● 只使用3张当前货币arr[i]情况下的最少张数,即dp[i-1][j-3*arr[i]]+3。
所有的情况中,最终取张数最小的。
所以 dp[i][j]=min{dp[i-1][j-k*arr[i]]+k(0<=k)}
 =>dp[i][j]=min{dp[i-1][j],min{dp[i-1][j-x*arr[i]]+x(1<=x)}}
 =>dp[i][j]=min{dp[i-1][j],min{dp[i-1][j-arr[i]-y*arr[i]]+y+1(0<=y)}}
 又有min{dp[i-1][j-arr[i]-y*arr[i]]+y(0<=y)} =>dp[i][j-arr[i]],
 所以,最终有:dp[i][j]=min{dp[i-1][j],dp[i][j-arr[i]]+1}。
 如果j-arr[i]<0,即发生越界了,说明arr[i]太大,用一张都会超过钱数j,
dp[i][j]=dp[i-1][j]即可。具体过程请参看如下代码中的minCoins1方法,
 整个过程的时间复杂度与额外空间复杂度都为O(N×aim),Narr的长度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值