假如如今有四种硬币类型:1角,2角,5角和1元。java
你如今是超市收银员,老板要求你每次都使用最少的硬币给用户找零。git
例如,用户须要找零6角,你须要找给他 一个5角 + 一个1角,这样只用到2个硬币,而不是找给他 六个1角 或者 三个2角。github
面对这样的问题咱们该如何思考呢?编程
假如当前已经选择了 i-1 枚硬币,当选择下一枚硬币 i 的时候,面对下面两种状况:数组
面对这两种选择咱们须要作的就是选择其中的最优解。spa
下面以找零6角为例进行一下推算。code
找零1角,可供选择的硬币为1角,那此时的最优解在选择这1角硬币和不选择这1角硬币中。blog
状况一:若是选择这1角硬币,这意味着须要的硬币数量 = ((找零1角 - 当前硬币金额 )所须要的硬币数量 )+ 1ip
找零1角 - 当前硬币金额 = 1 -1 = 0,而找零0角须要的硬币数量为0,因此第一种状况须要的硬币数量 = 0 + 1 = 1get
状况二:若是不选择这枚硬币,这意味着须要的硬币数量 = 以前 1 - 1 = 0 种硬币找零1角的最有解。
咱们知道若是硬币种类为0,咱们是没法进行找零的,也就是须要找零的硬币为无穷大。
显然状况一须要的硬币数量更少。此时的最优解为1。
同理咱们能够推论出后面的结果。下图显示了这个推算过程。
如上推算所示,咱们在推演时须要考虑一些边界条件:
一、若是当前没有硬币,是没法找零的,也就是不管多少硬币都没法找零。
二、若是须要找零的金额为0,那这时候也须要找零。
三、若是须要找零的金额数量小于硬币的面额,那这枚硬币就不须要使用。好比找零金额为6角,那1元的硬币确定是用不着的。
一、2 两个边界条件在找零钱前应该是默认成立的,因此在编写程序的时候须要将它们设置为初始条件。
边界条件3则是在咱们找零过程当中须要进行判断的,在编程时候应该写在找零程序中。
好了,说了这么多,仍是直接上代码方便快捷= =
package com.lkb.dp.problems; import java.util.Arrays; /** * @Description 硬币找零问题 * 假设只有 1角,2角,5角,1元的硬币, * 在超市结帐时,若是须要找零钱,收银员但愿将最少的硬币数找给顾客。那么,给定须要找的零钱数目,如何求得最少的硬币数呢? * @Author lkb * @CreateDate: 2019/6/1 */ public class ChargeProblem { public static void main(String[] args) { int[] coinsValues = {1,2,5,10}; Arrays.sort(coinsValues); int n = 6; int minCoinsNumber = charge(coinsValues, n); System.out.println(minCoinsNumber); } /** * 功能描述: 硬币找零问题 * @author lkb * @date 2019/6/1 * @param * @return int */ public static int charge(int[] coinKind, int money){ //这个数组保存最优解 //例如 value[2][5] 表示 使用 coinKind[0] coinKind[1] coinKind[2] 找零 money = 5 的最优解 int[][] value = new int[coinKind.length+1][money+1]; //边界条件1:若是硬币类型为0,则永远找不到合适的硬币找零 、 // 这里设置为最大值是由于咱们后续比较使用 for(int i=0; i<=money; i++){ value[0][i] = Integer.MAX_VALUE; } //边界条件2:若是钱为0,则永远找不到合适的硬币找零 for(int i=0; i<=coinKind.length; i++){ value[i][0] = 0; } for(int mon=1; mon<=money; mon++){ for(int kind=1; kind<=coinKind.length; kind++){ //边界条件2:若是硬币金额大于钱,则最优解是 上一步的最优解 if(coinKind[kind-1] > mon){ value[kind][mon] = value[kind-1][mon]; continue; } //当前最优解分为两种状况,须要在下面两种状况选择一种解最小的状况 //一个是使用了当前类型的硬币,value[kind][mon - coinKind[kind-1]] + 1 // 一个是没有使用当前类型的硬币, value[kind-1][mon] if((value[kind][mon - coinKind[kind-1]] + 1) < value[kind-1][mon]){ value[kind][mon] = value[kind][mon - coinKind[kind-1]] + 1; }else{ value[kind][mon] = value[kind-1][mon]; } } } return value[coinKind.length][money]; } }
你们也能够在这个地址下载源码,或者关注个人公众号,一块儿见证个人成长。