Leetcode 322. Coin Change 动态规划与 DFS 解法

换硬币

题目链接

题目描述

也是一道非常经典的题目。给定一个数组 coins,里面的每个数字代表可以使用的硬币面值,假设硬币的个数是无穷的。需要将一个大的数值,用尽可能少的硬币数目替换,使得它们面值相等。如果不存在这样的替换,返回 -1

Example 1:

Input: coins = [1, 2, 5], amount = 11
Output: 3 
Explanation: 11 = 5 + 5 + 1

解题方法

方法一:动态规划

动态规划。原始的思想是,使用 dp[i][j] 代表使用了第 i 个类型的硬币以后,能表示面值 j 的最小的硬币数目。假如 i+1 个硬币的面值是 c,更新的方式是 dp[i+1][j] = min(dp[i][j], dp[i][j - c] + 1)。因为这里 i+1 轮的所有结果,都只跟 i 轮的相关,所以可以只使用一个一维的数组,来降低空间复杂度。

总结来说,可以按如下进行计算:

  1. 一开始初始化空间大小为 amount + 1 的数组空间,dp[0] 置为 0,其余置为无穷。
  2. 按照 dp[i] = min(dp[i], dp[i - c] + 1) 更新
  3. 返回位置 amount 处的值

代码

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> dp(amount + 1, amount + 1);
        dp[0] = 0;
        for (int c : coins){
            for (int i = c; i <= amount; i ++){
                dp[i] = min(dp[i], dp[i - c] + 1);
            }
        }
        return dp[amount] == amount + 1 ? -1 : dp[amount];
    }
};

方法二:深度优先搜索

在空间中不断进行深度优先搜索。这里需要注意,如果不进行剪枝,会多进行很多不必要的运算。比如先搜索面值为 1 的硬币,会有很大的搜索空间,如果我们先搜索面值比较大的硬币,然后得到了一个解,如果我们接下来要搜索的时候,硬币数目已经大于了当前的解,那么就没必要进行搜索了。这样剪枝会带来很大的效率的提升。

方法二代码

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        // 先使用最大的
        sort(coins.rbegin(), coins.rend());
        int ans = INT_MAX;
        core(coins, amount, 0, 0, ans);
        return ans == INT_MAX ? -1 : ans;
    }
private:
    void core(vector<int> coins, int amount, int current_using, int current_count, int& ans){
        int coin = coins[current_using];
        if (current_using == coins.size() - 1){
            if (amount % coin == 0){
                ans = min(ans, current_count + amount / coin);
            }
        }
        else{
            // 先尽可能多的使用最大的
            // 在递归的时候进行剪枝,如果不能使得结果变得更好,就不要继续下去
            for (int k = amount / coin;
                k >= 0 && k + current_count < ans; k --){
                core(coins, amount - k * coin, current_using + 1, current_count + k, ans);
            }
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值