零钱兑换问题
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1: 输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2: 输入: coins = [2], amount = 3
输出: -1
说明: 你可以认为每种硬币的数量是无限的。
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change
解题思路:
如果你会爬楼梯问题,此题便会变得很容易理解了,
例如:
n阶楼梯,每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
此题链接在LeetCode的70题
https://leetcode-cn.com/problems/climbing-stairs/
那我们就可以把此题理解成,amount阶楼梯,每次你可以爬coins数组每个值对应个台阶,哪种方法爬的次数最少?也就是在不同方法中选取出攀爬最少的
此时列出dp状态转移方程:
状态dp[i] i表示台阶 dp[i]表示次数
dp方程:
dp[i]=min{dp[i-coins[j] + 1} 0<j<coins.size i > coins[j]
最后c++实现:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int coinChange(vector<int>& coins, int amount)
{
int maxn = amount + 1;
vector<int> dp(amount+1,maxn); //定义数组的大小及初始化
dp[0] = 0; //无面值为0的硬币,所以dp[0]=0
for(int i = 1; i <= amount; i++) { //每一阶楼梯对应的方法数
for(int j = 0; j < coins.size(); j++)
{
if(coins[j] <= i) {
dp[i] = min(dp[i],dp[i-coins[j]]+1); //较小次数
}
}
}
if(dp[amount] > amount)
return -1;
else
return dp[amount];
}
int main()
{
vector<int> coins;
coins.push_back(1);
coins.push_back(2);
coins.push_back(5);
int num = 11;
cout << coinChange(coins,num) << endl;
return 0;
}