题目描述:

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

示例 1:

输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:

输入: coins = [2], amount = 3
输出: -1
说明:
你可以认为每种硬币的数量是无限的。

初学动态规划类的问题要经历三次思考状态才能达到最终的求解。

以此题为例,首先想到的是采用暴力法求解问题,将问题分解为规模更小的子问题,而且子问题具有重叠性。

LeetCode_322_零钱兑换_时间复杂度

class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
if (amount == 0) return 0;
int ans = INT_MAX;
for (int coin : coins) {
// 金额不可达
if (amount - coin < 0) continue;
int subProb = coinChange(coins, amount - coin);
// 子问题无解
if (subProb == -1) continue;
ans = min(ans, subProb + 1);
}
return ans == INT_MAX ? -1 : ans;
}
};

这种递归方式,虽然可以得到正确解,但是超时,就是计算了大量的重复子问题,这需要进行剪枝,来缩减时间复杂度。

参考题解答案

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

}
};

LeetCode_322_零钱兑换_时间复杂度_02