翻译工作
给你一个数组,元素代表不同面值的硬币,一个整数,代表总钱数。用最少的硬币凑出总钱数,若不能凑出总钱数则返回-1。
你可能需要给出一系列特定的面值;
示例1:
输入:coins = [1,2,5],amount =11
输出:3
解释:11=5+5+1
示例2:
输入:coins = [2],amount = 3
输入:-1
示例3:
输入:coins = [1],amount = 0
输出:0
方法论:
以coins=[2,5,7],m=27为例
1.确定状态
数组f[i]/f[i][j]代表什么?
确定状态要有2个意识:1)最后一步 2)子问题
1)最后一步
假设最优策略是K枚硬币组成,即a1,a2,a3,……ak,a1+……ak = 27
27-ak | ak |
K-1枚硬币 | 最后一枚 |
注:2个关键
a.不关心前面的硬币是怎么拼出27-ak的(可能1种可能100种),甚至还不知道ak和K,但能确定前面的硬币拼出了27-ak。
b.因为是最优策略,所以拼出27-ak的硬币数一定是最优解。
2)子问题
用最少的硬币可以拼出27-ak。
设f[x]表示永最少硬币拼出x,ak取值为2,5,7,m=27
f[27]的取值可能为f[27-2]+1,f[27-5]+1,f[27-7]+1,由题取
f[27] = min{ f[27-2]+1,f[27-5]+1,f[27-7]+1}
2.转移方程
f[x]代表拼出x的最少硬币数
对于任意x,有f[x] = min{ f[x-2]+1,f[x-5]+1,f[x-7]+1}
3.初始条件,边界情况
f[0] = 0,f[x] = 正无穷表示当前硬币拼不出x
4.计算顺序
初始f[0] = 0
计算f[1],f[2]……f[27]
示例
#include<iostream>
#include<malloc.h>
using namespace std;
//LintCode;Coin Change
//3种硬币2元 5元 7元,买一本书27元
//如何用最少的硬币组合正好付清,不需要对方付清f(x)表示买一本27元的书凑出最少的硬币
/******66656565{2,5,7} *** 27*/
int CoinChange(int A[], int m) {
int MAXN = 32001;
int *f = new int[m+1];
f[0] = 0;
int lenA = 0;
for (int i = 0; A[i] >= 0; i++) {
lenA++;
}
int i, j;
for (i = 1; i <= m; i++) { //1 2 3...m
f[i] = MAXN;
for ( j = 0; j < lenA; j++) { //2 5 7
if (i >= A[j] && A[i - A[j]] != MAXN) { //所需金额大于面值且当前面值能凑出所需金额
f[i] = f[i] < (f[i - A[j]] + 1) ? f[i] : (f[i - A[j]] + 1) ;
}
}
}
if (f[m] == MAXN) {
f[m] = -1;
}
return f[m];
}
int main() {
//Coinchange
int A[] = { 2,5,7 };
int m = 27;
cout<<CoinChange(A,m);
return 0;
}