钱币问题简单分析

钱币问题

如果现在有10元钱,有3种零钱,分别是[5,2,1]元,请说出找零钱有多少种方式。


先用手算,我们会分别求出当第一位为5,2,1时的情况。

计算过程如下:

  1. 以5为开头
    1. 5 5
    2. 5 2 2 1
    3. 5 2 1 1 1
    4. 5 1 1 1 1 1
  2. 以2为开头
    1. 2 2 2 2 2
    2. 2 2 2 2 1 1
    3. 2 2 2 1 1 1 1
    4. 2 2 1 1 1 1 1 1
    5. 2 1 1 1 1 1 1 1 1
  3. 以1为开头
    1. 1 1 1 1 1 1 1 1 1 1

分析:

  1. 在计算中,我们计算以2为开头时,并不会把5列入,因为我们知道5 2 2 1和2 5 2 1是一样的。
  2. 计算用了3种,和零钱的种类相同
  3. 在这期间,结束的标志为当所有零钱加起来等于需要的钱数10,我们就会认为结束了
  4. 在此期间,我们会自动忽略加起来会超过数值的选项,比如5 2 5

所以我们的思路就是:

  1. 将给定的钱数看做一个排序好的列表(即使他是[2, 5, 1])

  2. 对于列表的第一种钱,我们可以选择 拿或者不拿

    假定钱数是money = m,可选的种类为kind = k,零钱列表为L

    1. 不拿,那我们可以拿其他几种,我们可以拿的种类变为 k - 1
    2. 拿第一种钱,则剩余的钱数为 m - L[0]。剩余的钱可以再从目前所有种类的零钱中再执行步骤2
  3. 我们对每个都执行步骤2

  4. 结果判断:

    1. m = 0,则刚好选择完,钱可以被兑换成零钱,此方案可行。
    2. k = 0,可选的种类已经没有了。
    3. m < 0,此方案行不通,例如2 5 5的情况下,m = -2。

Java代码如下:

public class DealMoney {
    private static int[] MONEY_LIST = { 2, 5, 1 };

    public static int calculate(int money) {
        return mainBody(money, MONEY_LIST.length);
    }

    private static int mainBody(int money, int kind) {
        if (money == 0) {
            return 1;
        }

        if (kind <= 0 || money < 0) {
            return 0;
        }

        return not_select(money, kind) + select(money, kind);
    }

    private static int not_select(int money, int kind) {
        kind--;
        return mainBody(money, kind);
    }

    private static int select(int money, int kind) {
        int index = MONEY_LIST.length - kind;

        return mainBody(money - MONEY_LIST[index], kind);
    }

    public static void main(String[] args) {
        System.out.println(calculate(10));
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42254247/article/details/106319409