LeetCode 322 Coin Change (完全背包)

本文探讨了如何用最少数量的硬币凑成指定金额的问题,并给出了一种使用动态规划解决该问题的方法。通过两个具体例子说明了算法的运行过程。

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

Example 1:
coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)

Example 2:
coins = [2], amount = 3
return -1.

Note:
You may assume that you have an infinite number of each kind of coin.


题目链接:https://leetcode.com/problems/coin-change/

题目分析:因为个数是无穷的,所以就是一个完全背包计数问题,dp[i]表示合到i所需要的最少个数,dp初始化为无穷大,dp[0] = 0
public class Solution {
    
    public int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount + 1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;
        for(int i = 0; i < coins.length; i ++) {
            for(int j = 0; j <= amount; j ++) {
                int pre = j - coins[i];
                if(pre >= 0 && dp[pre] < Integer.MAX_VALUE) {
                    dp[j] = Math.min(dp[j], dp[pre] + 1);
                }
            }
        }
        if(dp[amount] == Integer.MAX_VALUE) {
            return -1;
        }
        return dp[amount];
    }
}


### 完全背包问题的动态规划解法 #### 1. 定义与背景 完全背包问题是经典的动态规划问题之一,其特点是每种物品可以无限次选取。给定一组物品及其对应的重量 `weight` 和价值 `value`,以及一个最大承重为 `W` 的背包,目标是在不超过背包容量的前提下最大化所选物品的价值。 对于该问题,可以通过构建动态规划表来实现最优解。以下是基于一维数组优化后的解决方案[^2]: --- #### 2. 动态规划的核心思路 定义状态转移方程如下: - 设 `dp[j]` 表示当前状态下,当背包容量为 `j` 时所能获得的最大价值。 - 对于每一个物品 `i`,如果将其加入背包,则更新状态为: \[ dp[j] = \max(dp[j], dp[j - weight[i]] + value[i]) \] 由于完全背包允许同一种物品多次被选择,在遍历过程中需调整循环顺序以确保每次计算都考虑了重复使用的可能性。具体而言,外层应枚举所有物品,而内层则按 **从小到大** 的顺序遍历背包容量 \( j \)。 --- #### 3. Python 实现代码 以下是一个典型的完全背包问题求解代码框架,适用于 LeetCode 上的相关题目(如零钱兑换等问题): ```python def completeKnapsack(weights, values, capacity): n = len(weights) dp = [0] * (capacity + 1) for i in range(n): # 遍历每个物品 for j in range(weights[i], capacity + 1): # 遍历背包容量,从小到大 dp[j] = max(dp[j], dp[j - weights[i]] + values[i]) return dp[capacity] ``` 上述代码通过两层嵌套循环完成状态转移过程。注意这里采用了一维数组存储中间结果,并且内部循环按照从小到大的方式访问索引来支持多重选择行为。 另外针对特定应用场景比如硬币找零问题(LeetCode No.322),可以直接修改逻辑适应实际需求[^3]: ```python class Solution: def coinChange(self, coins: List[int], amount: int) -> int: dp = [float('inf')] * (amount + 1) dp[0] = 0 for coin in coins: for x in range(coin, amount + 1): dp[x] = min(dp[x], dp[x - coin] + 1) return dp[amount] if dp[amount] != float('inf') else -1 ``` 此版本专注于最小化所需数量而非总值最大化,因此初始化条件有所变化并引入无穷大表示不可达情况。 --- #### 4. 时间复杂度分析 整个算法运行时间为 O(N*W),其中 N 是物品数目,W 是背包容量。相比原始暴力搜索方法呈指数增长的趋势显著降低开销[^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值