zoukankan      html  css  js  c++  java
  • 数学基础:三、动态规划2(求解凑齐钱的最小张数)

    凑齐钱的最小张数概念:

    比如只有2块、3块和5块钱若干,问凑齐100块钱最小需要几张钱能凑齐?(20张5块的,所以是20张)

    前面一篇求解编辑距离时,有现成的状态转移方程,可是这种凑齐面值的没有现成的公式,只能自己去推导。

    当然我们可以利用求余数求解,凑齐98块,需要98/5=19…3,所以为19张5块+1张3块(一共20张)

    但这个可能用余数可能更方便,但对于动态归划方法,可能是个思路

    比如只有2、3、7块,用表格推导的过程如下:
    在这里插入图片描述
    而如果只有2、5、9块,它的推导如下:
    在这里插入图片描述
    根据推导过程,写出的算法如下:

    public class Lesson10_1 {
        // 钱币币种可选的值,自己可随意改
        private static final int[] coins = {2, 5, 9};
    
        // 如果不加变量保存,每次都要重复递归计算
        private static Map<Integer, Integer> hasCount = new HashMap<>();
    
        // 传入总金额和可选币种,返回凑够该金额的最小数量,返回null表示没有找到
        // 为null表示凑不齐这个钱(商场买菜要1块钱,可选币种最小值要2块,我们不能傻得给人家2块不找零,此时就是凑不齐)
        public static Integer getCount(int total, int[] coins) {
            // 如果之前已计算过该金额的,直接返回,无需递归调用了
            if (hasCount.containsKey(total)) {
                return hasCount.get(total);
            }
            // 递归减到了负数,也没凑齐,就是没找到
            if (total < 0) {
                return null;
            } else if (total == 0) {// 金额为0,那需要的数量肯定为0
                return 0;
            } else {
                int length = coins.length;
                // 保存可选币种中,每种所需的最小数量
                Integer[] min = new Integer[length];
                for (int i = 0; i < length; i++) {
                    // 比如求凑20块钱,可选值是5块钱,那递归求凑15块+1即可    C20(5) = C15(5) + 1
                    // 再比如求凑18块钱,可选值2块钱,那递归求凑16块+1即可    C18(2) = C16(2) + 1
                    // C n (m) = C n-m (m) + 1
                    Integer tmpResult = getCount(total - coins[i], coins);
                    // 返回值为空,说明递归调用到 if (total < 0) 时返回了空,没有凑够该值
                    min[i] = tmpResult != null ? (tmpResult + 1) : null;
                }
                // 去除空值
                List<Integer> resultList = Arrays.stream(min).filter(e -> e != null).collect(Collectors.toList());
                // 如果不为空,那最小值就是所需的最小个数
                Integer result = resultList.size() > 0 ? resultList.stream().mapToInt(e -> e).min().getAsInt() : null;
                // 放到map中,防止后续重复递归计算
                hasCount.put(total, result);
                return result;
            }
        }
    
        public static void main(String[] args) {
            Integer count = getCount(102, coins);
            System.out.println(count);
        }
    }
    
  • 相关阅读:
    How to disable daily upgrade and clean on Ubuntu 16.04
    跟李沐学Ai 03 安装【动手学深度学习v2】
    When using 'npm' it requires me to login to github
    Wrong detect of Parsing error: invalid-first-character-of-tag-name in expression.
    18.04: a stop job is running for unattended upgrades shutdown
    NCSC recommend against forcing regular password expiry,
    OWASP Testing for Weak Password Policy--> When must a user change their password
    NIST Special Publication 800-63: Digital Identity Guidelines Frequently Asked Questions
    Mo Tu We Th Fr Sa Su
    工程变更-ECN,ECO,ECR,ECA
  • 原文地址:https://www.cnblogs.com/dulinan/p/12032997.html
Copyright © 2011-2022 走看看