题目
给定数组 arr,arr 中所有的值都为正数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim,代表要找的钱数,求换钱有多少种方法。
举例
arr=[5,10,25,1],aim=0.
组成0元的方法有1种,就是所有面值的货币都不用。所以返回1。
arr=[5,10,25,1],aim=15。
组成15元的方法有6种,分别为3张5元、1张10元+1张5元、1张10元+5张1元、10张1元+1张5元、2张5元+5张1元和15张1元。所以返回6。
arr=[3,5],aim=2.
任何方法都无法组成2元。所以返回0。
解答
题目其实可以转化为 aim 由 arr 中的数组成,arr中的数可以重复使用,使用的总次数最少为多少。
这里可以使用动态规划的解法,假设 dp[i] 表示使用arr中数组成i的最少数目,动态规划公式如下所示
dp[i] = min(dp[i - vec[j]]) + 1 ,j >= 0 && j <= arr.size()
dp初始为 aim 大小且每个值为 -1 的数组,代码如下所示,具体思路可以参考《程序员代码面试指南》书籍
代码实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class solution {
public:
int searchMoney(const vector<int>& vec, int aim) {
if (0 == aim) {
return 0;
}
vector<int> dp(aim + 1, -1);
dp[0] = 0;
for (int i = 1; i <= aim; i++) {
for (int j = 0; j < vec.size(); j++) {
if (i < vec[j]) {
// i小于 vec[j] 表示i无法由vec[j]组成
continue;
} else if (i == vec[j]) {
// i 等于 vec[j] 表示i刚好可以由vec[j]组成
dp[i] = 1;
} else if (dp[i - vec[j]] != -1){
// dp[i - vec[j]] 为-1的话,表示i - vec[j]无法组成
dp[i] = -1 == dp[i] ? dp[i - vec[j]] + 1 : min(dp[i], dp[i - vec[j]] + 1);
}
}
}
return dp[aim];
}
};
int main(int argc, const char* argv[]) {
//arr = [5, 2, 3] aim 为 20
//arr = [5, 2, 3] aim 为 0
//arr = [5, 3] aim 为 2
solution a;
vector<int> v1 = {5, 2, 3};
cout << a.searchMoney(v1, 5) << endl;
cout << a.searchMoney(v1, 0) << endl;
cout << a.searchMoney(v1, 1) << endl;
return 0;
}
654

被折叠的 条评论
为什么被折叠?



