518. 零钱兑换 II(记忆化搜索+排序剪枝、DP动态规划) - 力扣(LeetCode)

零钱兑换 II
给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。

假设每一种面额的硬币有无限个。

题目数据保证结果符合 32 位带符号整数。

示例 1:

输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

代码

AC代码

记忆化搜索+排序剪枝

class Solution {
    public int change(int amount, int[] coins) {
        int n = coins.length;
        dict = new int [n][amount+1];
        for(int i=0; i<n; ++i){
            Arrays.fill(dict[i],-1);
        }
        Arrays.sort(coins);  //排序后剪枝,这里不排序也能过
        int ans = dfs(0,amount,coins);
        return ans;
    }   
    int [][]dict;
    int dfs(int idx,int amount,int []coins){
        if(amount==0){
            return 1;
        } 
        if(dict[idx][amount]!=-1) return dict[idx][amount];

        int ans = 0;
        for(int i=idx; i<coins.length; ++i){
            if(amount-coins[i]>=0){  //一个剪枝
                ans += dfs(i, amount-coins[i], coins);
            }
            else break;  //如果不排序,这行代码去掉
        }
        dict[idx][amount] = ans;
        return ans;
    }
}

Java提交击败了8%,再优化的话暂时没有思路
在这里插入图片描述

Debug版本的代码

可输出路径
518. 零钱兑换 II(记忆化搜索+排序剪枝、DP动态规划) - 力扣(LeetCode)_第1张图片

class Solution {
    public int change(int amount, int[] coins) {
        dict = new int [amount+1];
        Arrays.fill(dict,-1);
        int ans = dfs(0,amount,coins,new LinkedList<>());
        int n = coins.length;
        for(List<Integer> path : res){
            for(Integer p : path)
                System.out.print(p+",");
            System.out.println();
        }
        return ans;
    }   
    int []dict;
    List<List<Integer>> res = new LinkedList<>();
    int dfs(int idx,int amount,int []coins, List<Integer>path){
        if(amount==0){
            res.add(new LinkedList<>(path));
            return 1;
        } 
        if(amount<0) return 0;
        // if(dict[amount]!=-1) return dict[amount];

        int ans = 0;
        for(int i=idx; i<coins.length; ++i){
            if(amount-coins[i]>=0){
                path.add(coins[i]);
                ans += dfs(i, amount-coins[i], coins,path);
                path.remove(path.size()-1);
            }
        }
        // dict[amount] = ans;
        return ans;
    }
}

DP代码

class Solution {
    /*
    dp[i][j]   = dp[i-1][j] + dp[i-1][j-c] + dp[i-1][j-2*c]+...
    dp[i][j-c] = dp[i][j-c] + dp[i-1][j-2*c] + dp[i-1][j-3*c]+...
    dp[i][j] = dp[i-1][j]+dp[i][j-c]
    */
    public int change(int amount, int[] coins) {
        int n = coins.length;
        int dp[][] = new int[n+1][amount+1];
        for(int i=0; i<=n; ++i)
            dp[i][0] = 1;

        for(int i=1; i<=n; ++i){
            for(int j=1; j<=amount; ++j){
                if(j-coins[i-1]>=0)
                    dp[i][j] = dp[i-1][j]+dp[i][j-coins[i-1]];
                else dp[i][j] = dp[i-1][j];
            }
        }
        return dp[n][amount];
    }
}

你可能感兴趣的:(动态规划,leetcode,leetcode,动态规划,剪枝)