零钱兑换
思路
这是一个完全背包问题
材料是硬币,背包是和
用动态规划来解
确定dp数组含义
令 dp[i] 为达成数额为i最少需要dp[i]个硬币
确定递推公式
对于 dp[i] 来说,假设当前兑换的硬币值为coin[j],那么 dp[j] 肯定可由 dp[i-coin[j]] 推出
所以有dp[i]=min(dp[i-coin[j]],dp[i])
确定初始化
要求最小值,为防止小值被覆盖,初始化必须全部为最大值
确定遍历顺序
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
本题物品,在背包
代码
来自代码随想录
class Solution {
public int coinChange(int[] coins, int amount) {
int max = Integer.MAX_VALUE;
int[] dp = new int[amount + 1];
//初始化dp数组为最大值
for (int j = 0; j < dp.length; j++) {
dp[j] = max;
}
//当金额为0时需要的硬币数目为0
dp[0] = 0;
for (int i = 0; i < coins.length; i++) {
//正序遍历:完全背包每个硬币可以选择多次
for (int j = coins[i]; j <= amount; j++) {
//只有dp[j-coins[i]]不是初始最大值时,该位才有选择的必要
if (dp[j - coins[i]] != max) {
//选择硬币数目最小的情况
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
}
}
}
return dp[amount] == max ? -1 : dp[amount];
}
}
完全平方数
思路
和上题一样,也是完全背包问题。
- 令dp[i]为返回和为i的完全平方数的最少数量
- 可以看出以j为和的完全平方数最少数量可由,以j-i*i为和的完全平方数的最少数量加一得出,写成表达式为dp[j]=dp[j-i*i]+1
- 要求最小那么dp初始化需要初始化最大才能保证dp不被覆盖
- 本题是求组合数,无顺序关系,因而先遍历物品(1~根号n ),再遍历背包(1~n)
代码
class Solution {
public int numSquares(int n) {
int max = Integer.MAX_VALUE;
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
// 当和为0时,组合的个数为0
dp[0] = 0;
// 遍历物品
for (int i = 1; i * i <= n; i++) {
// 遍历背包
for (int j = i * i; j <= n; j++) {
if (dp[j - i * i] != max) {
dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
}
}
}
return dp[n];
}
}