【刷题之路】零钱凑整问题

有数组penny,penny中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim(小于等于1000)代表要找的钱数,求换钱有多少种方法。

经典的动态规划问题,首先需要确定状态,然后叠加即可。

首先确定初始状态,当目标钱数为0时,无论如何只有一种方法,即不用任何面值的钱

当目标钱数小于面额最小的钱时,方法数为零

定义一个二维数组,i为所使用的面额index, j为目标钱数,我们需要按行来填满这个数组,数组的最后一个元素即为所求。

假设penny中共有,1,2,5三种面额钱数,需要凑齐100块

res[0][0]  即为使用1块钱,来凑齐0元,则只有一种方法,res[0][0]=1,res[0][1]同理也等于一,直到100,

res[1][0] 即为使用2块钱来凑0元,则只有一种方法,不难看出,res[i][0]=1。这样。我们就定义好了初始状态,第一行全为1,第一列全为1

当求res[2][6]时,很显然包括两部分,首先,不使用当前的面额,只使用上一种面额,则为res[1][6],第二部分,当需要求使用当前面额时,问题就变成了用一张5块以及若干1块2块来达到目标金额的方法也就是res[2][1]所以res[2][6]=res[1][6]+res[2][1]

总结上述规则可知,res[i][j]也就等于res[i-1][j]+res[i][j-penny[i]](此处需要说明一下为什么只减去1次当前面额:有人会疑问如果我想用两张当前面额呢?其实减去当前面额后,如果目标值仍大于当前面额,则所加上的res[i][j-penny[i]]在计算的时候,一定是res[i-1][j-penny[i]]+res[i][j-penny[i]-penny[i]]计算出来的,也就是说之前的已经包含了使用一张当前面额的情况,加上本次又一次使用当前面额,即使用两张当前面额的情况,实际上已经算过了)

这样得到了递推公式,程序如下

class Exchange {
public:
    int countWays(vector<int> penny, int n, int aim) {
        // write code here
        vector<int> sub(aim+1);
        vector<vector<int>> res(n,sub);
        int i,j;
        for(i=0;i<=aim;i++){
            if(i%penny[0]==0) res[0][i]=1;
        }
        for(i=1;i<n;i++){
            res[i][0]=1;
            for(j=1;j<=aim;j++){
                if(j-penny[i]>=0) res[i][j]=res[i-1][j]+res[i][j-penny[i]]; //注意此处需要判断,如果减去小于0的话,显然不能用当前面额的纸币
                else res[i][j]=res[i-1][j];
            }
        }
        return res[n-1][aim];
        
    }
};

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
零钱问题是指给定一定面额的硬币,以及一个总金额,求出能够凑出该总金额的最少硬币数。这是一个经典的动态规划问题,可以使用Java语言来实现。 首先,我们需要定义一个函数来解决凑零钱问题。该函数需要接收两个参数:硬币面额数组和目标金额。函数的返回值应该是能够凑出目标金额的最少硬币数。 接下来,我们可以使用一个一维数组来记录每个金额所需要的最少硬币数。数组的长度应该是目标金额加一,因为我们需要计算从0到目标金额的最少硬币数。 然后,我们可以使用一个循环来遍历每个金额,并计算出凑出该金额所需要的最少硬币数。具体的计算方法是:对于每个硬币面额,如果该面额小于等于当前金额,那么就可以使用该硬币来凑出当前金额。此时,我们需要使用之前计算出的最少硬币数来更新当前金额所需要的最少硬币数。具体的更新方法是:将当前金额减去硬币面额,然后加上使用该硬币所需要的最少硬币数。最后,我们需要在所有硬币面额中选择最小的硬币数作为当前金额所需要的最少硬币数。 最后,我们可以返回数组中最后一个元素作为凑出目标金额的最少硬币数。 下面是Java代码实现: ```java public int coinChange(int[] coins, int amount) { int[] dp = new int[amount + 1]; Arrays.fill(dp, amount + 1); dp[0] = 0; for (int i = 1; i <= amount; i++) { for (int j = 0; j < coins.length; j++) { if (coins[j] <= i) { dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); } } } return dp[amount] > amount ? -1 : dp[amount]; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值