暴力的な再帰方法:
/*
暴力递归
// 状态 目标金额
// 选择 coins数组中所有的硬币面额
// 函数定义 凑出总数为amount,至少需要coinChange(coins, amount)枚硬币
// base_case: amount==0时,需要0枚硬币
// amount<0时,不可能凑出
*/
// coinChange([1,2,5], 11) = 1 + min(coinChange([1,2,5],10), coinChange([1,2,5],9), coinChange([1,2,5],6));
int min(int x, int y) {
return x < y ? x : y;
}
int coinChange(int *coins, int amount) {
// base_case
if (amount == 0) return 0;
if (amount < 0) return -1; //异常值
int res = __INT32_MAX__;
for (int i = 0; i < 3; i++) {
// 计算子问题的结果
int subProblem = coinChange(coins, amount - coins[i]);
if (subProblem == -1) continue;
res = min(res, subProblem + 1);
}
return res == __INT32_MAX__? -1: res;
}
int main() {
int coins[] = {1, 2, 5};
int res = coinChange(coins, 11);
printf("amount=%d,need less [%d] coins\n",11, res);
}
ps:量変数が大きすぎると、実行効率が非常に低くなります。メモを使用して効率を向上させ、不要な繰り返しの冗長な計算を減らします。
覚書法:
/*
备忘录递归
// 状态 目标金额
// 选择 coins数组中所有的硬币面额
// 函数定义 凑出总数为amount,至少需要coinChange(coins, amount)枚硬币
// base_case: amount==0时,需要0枚硬币
// amount<0时,不可能凑出
*/
// coinChange([1,2,5], 11) = 1 + min(coinChange([1,2,5],10), coinChange([1,2,5],9), coinChange([1,2,5],6));
#include <stdio.h>
#include <string.h>
int *memo = NULL;
int min(int x, int y) {
return x < y ? x : y;
}
int coinChange(int *coins, int amount) ;
int dp(int *coins, int amount) {
// base_case
if (amount == 0) return 0;
if (amount < 0) return -1; //异常值
// 查询备忘录
if (memo[amount] != -666)
return memo[amount];
int res = __INT32_MAX__;
for (int i = 0; i < 3; i++) {
// 计算子问题的结果
int subProblem = dp(coins, amount - coins[i]);
if (subProblem == -1) continue;
res = min(res, subProblem + 1);
}
memo[amount] =( res == __INT32_MAX__? -1: res);
return memo[amount];
}
int coinChange(int *coins, int amount) {
//开辟一块备忘录
memo = new int[amount + 1];
for (int i=0; i< amount+1; ++i) {
memo[i] = -666;
}
return dp(coins, amount);
}
int main() {
int coins[] = {1, 2, 5};
int res = coinChange(coins, 11);
printf("amount=%d,need less [%d] coins\n",11, res);
}