22.3:货币问题3

  • arr是货币数组,其中的值都是正数。再给定一个正数aim。
  • 每个值都认为是一张货币,
  • 认为值相同的货币没有任何不同,
  • 返回组成aim的方法数
  • 例如:arr = {1,2,1,1,2,1,2},aim = 4
  • 方法:1+1+1+1、1+1+2、2+2
  • 一共就3种方法,所以返回3

暴力方法

	public static class Info {
        public int[] coins;
        public int[] zhangs;

        public Info(int[] coins, int[] zhangs) {
            this.coins = coins;
            this.zhangs = zhangs;
        }
    }

    //建立Info结构
    public static Info createInfo(int[] arr) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < arr.length; i++) {
            if (!map.containsKey(arr[i])) {
                map.put(arr[i], 1);
            } else {
                map.put(arr[i], map.get(arr[i]) + 1);
            }
        }
        //词频统计完成
        int[] coins = new int[map.size()];
        int[] zhangs = new int[map.size()];
        int index = 0;
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            coins[index] = entry.getKey();
            zhangs[index] = entry.getValue();
            index++;
        }
        return new Info(coins, zhangs);
    }

    public static int coinsWay(int[] arr, int aim) {
        if (arr == null || arr.length == 0 || aim < 0) {
            return 0;
        }
        return process(createInfo(arr), aim, 0);
    }

    //从左到右模型
    //返回满足条件的方法总数。
    public static int process(Info info, int aim, int index) {
        if (index == info.coins.length) {
            return aim == 0 ? 1 : 0;
        }
        int[] coins = info.coins;
        int[] zhangs = info.zhangs;
        int ways = 0;
        //当前位置到底拿几张。
        for (int zhang = 0; zhang <= zhangs[index] && aim - coins[index] * zhang >= 0; zhang++) {
            ways += process(info, aim - zhang * coins[index], index + 1);
        }
        return ways;
    }

dp模型

在这里插入图片描述

    public static int dp(int[] arr, int aim) {
        if (arr == null || arr.length == 0 || aim < 0) {
            return 0;
        }
        Info info = createInfo(arr);
        int N = info.coins.length;
        int[] coins = info.coins;
        int[] zhangs = info.zhangs;
        int[][] dp = new int[aim + 1][N + 1];
        dp[0][N] = 1;

        //当前位置到底拿几张。
        for (int L = N - 1; L >= 0; L--) {
            for (int H = 0; H <= aim; H++) {
                int ways = 0;
                for (int zhang = 0; H - coins[L] * zhang >= 0 && zhang <= zhangs[L]; zhang++) {
                    ways += dp[H - zhang * coins[L]][L + 1];
                }
                dp[H][L] = ways;
            }
        }
        return dp[aim][0];
    }

dp方法优化

//我不想枚举,想用临近位置代替。
public static int dp2(int[] arr, int aim) {
    if (arr == null || arr.length == 0 || aim < 0) {
        return 0;
    }
    Info info = createInfo(arr);
    int N = info.coins.length;
    int[] coins = info.coins;
    int[] zhangs = info.zhangs;
    int[][] dp = new int[aim + 1][N + 1];
    dp[0][N] = 1;
    //当前位置到底拿几张。
    for (int L = N - 1; L >= 0; L--) {
        for (int H = 0; H <= aim; H++) {
            int key = dp[H][L + 1];
            if (H - coins[L] >= 0) {
                key += dp[H - coins[L]][L];
            }
            if (H - coins[L] - zhangs[L] * coins[L] >= 0) {
                key -= dp[H - coins[L] - zhangs[L] * coins[L]][L + 1];
            }
            dp[H][L] = key;
        }
    }
    return dp[aim][0];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HackerTerry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值