一.题目描述
给定数组arr,arr中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个aim,代表要找的钱数,求组成aim的最少货币数。如果无解,请返回-1。
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。
二.算法(c++动态规划)
我们采用一维dp[j]来进行动态规划:
(1)状态dp[j]定义:N件物品,背包容量j下的最优解。
(2)注意枚举背包容量j必须从m开始。
下面是完整的代码
class Solution { public: int minMoney(vector<int>& arr, int aim) { int dp[aim+5]; dp[0]=0; //刚开始初始化,都是正无穷 for(int i=1;i<=aim;i++) dp[i]=1e9; for(int i=0;i<arr.size();i++){ for(int j=arr[i];j<=aim;j++){ //状态转移 dp[j]=min(dp[j],dp[j-arr[i]]+1); } } //要是dp[m]的最后大小不是无穷 表示有解 否则无解 if(dp[aim]!=1e9) return dp[aim]; return -1; } };
时间复杂度: 其中m表示需要凑的钱数,需要二重循环
空间复杂度: 需要开辟空间来存储方案数
优缺点:代码实现简单,而且容易理解
三.算法(java实现)
思路和上面的算法大致一样,下面是完整代码:
import java.util.*; public class Solution { public int minMoney (int[] arr, int aim) { int[] dp=new int[aim+1]; dp[0]=0; //刚开始初始化,都是一个较大的数 for(int i=1;i<dp.length;i++){ dp[i]=1000000; } for(int i=0;i<arr.length;i++){ for(int j=arr[i];j<=aim;j++){ dp[j]=Math.min(dp[j],dp[j-arr[i]]+1); } } //要是dp[m]的最后大小不是无穷 表示有解 否则无解 if(dp[aim]!=1000000) return dp[aim]; else return -1; } }
时间复杂度: 其中m表示需要凑的钱数,需要二重循环
空间复杂度: 需要开辟空间来存储方案数
优缺点:代码实现简单,而且容易理解