硬币找零问题

假如如今有四种硬币类型: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];
    }


}

 

你们也能够在这个地址下载源码,或者关注个人公众号,一块儿见证个人成长。

相关文章
相关标签/搜索