换钱的最少货币数

在这里插入图片描述

分析

如果arr的长度为N, 则生成一个行数为N, 列数为aim+1的动态规划表dp[N][aim+1], dp[i][j]的含义为:在可以任意使用arr[0…i]货币的情况下,组成j所需的最小张数。

设: arr=[5,2,3,1] aim = 5
1、dp[0…N-1][0]的值表示找钱数为0时需要的最少张数,所以全设为0。(矩阵的第一列)

2、dp[0][0…aim]的值表示只能使用arr[0]货币也就是5的情况下,找0 ,1,2,3,4,5的钱的情况下。其中无法找开的一律设为32位的最大值,记为max.

3、剩下的位置依次从左到右,再从上到下计算。假设计算到(i,j)位置,dp[i][j]的值可能来自下面的情况:
完全不使用当前货币arr[i]情况系的最少张数,即dp[i-1][j]的值
只使用一张当前货币arr[i]的情况下的最少张数,即dp[i-1][j-arr[i]]+1 其中 j-arr[i]的值为使用了一张arr[i]后,还需要找多少钱。 i-1是指使用arr[i]之前的钱来兑换
只使用两张当前货币arr[i]的情况下的最少张数,即dp[i-1][j-2arr[i]]+2
只使用三张当前货币arr[i]的情况下的最少张数,即dp[i-1][j-3
arr[i]]+3
所有情况中,取最小的纸张数。所以:

dp[i][j] = min{dp[i-1][j], min{dp[i-1][j-x*arr[i]]+x (x >= 1)}} ==>

设x-1 = y >= 0 ==> x = y +1代入得

dp[i][j] = min{dp[i-1][j], min{dp[i-1][j-arr[i]-y*arr[i]]+y+1 (y>=0)}}

又因为min{dp[i-1][j-arr[i]-yarr[i]+ y] = dp[i][j-arr[i]] ,因为其中 dp[i-1][j-yarr[i]+y] = dp[i][j]
    最终有: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]即可。
代码:

import java.util.*;


public class Solution {
    /**
     * 最少货币数
     * @param arr int整型一维数组 the array
     * @param aim int整型 the target
     * @return int整型
     */
    public int minMoney (int[] arr, int aim) {
        if(arr == null || arr.length == 0 || aim < 0){
            return -1;
        }
        int[][] dp = new int[arr.length][aim+1];
          int max = Integer.MAX_VALUE;
        //设置第一行
        for(int j=1; j <= aim; j++){
            dp[0][j] = max;
            if(j-arr[0] >= 0 && dp[0][j-arr[0]] != max ){
                dp[0][j] = dp[0][j-arr[0]] + 1;
            }
        }
        int left = 0;
        for(int i=1; i < arr.length; i++){
            for(int j=1; j <=aim; j++){
                left = max;
                if(j-arr[i] >=0 && dp[i][j-arr[i]] != max){
                    left = dp[i][j-arr[i]] + 1;
                }
                dp[i][j] = Math.min(left, dp[i-1][j]);
            }
        }
        return dp[arr.length-1][aim] != max ? dp[arr.length-1][aim] : -1;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值