322. 零钱兑换
题意
给定不同面额的硬币 coins
和一个总金额 amount
。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1
。
你可以认为每种硬币的数量是无限的。
思路
记忆化搜索
- 定义 F ( S ) F(S) F(S) 为组成金额 S S S所需要最小的硬币数。
- 定义 [ c 0 , … , c n − 1 ] [c_0,\dots,c_{n-1}] [c0,…,cn−1] 为可供选择的硬币面额
存在如下转移方程
F
(
S
)
=
min
i
=
0
⋯
n
−
1
F
(
S
−
c
i
)
+
1
s
u
b
j
e
c
t
t
o
S
−
c
i
≥
0
F
(
S
)
=
0
,
w
h
e
n
S
=
0
F
(
S
)
=
−
1
,
w
h
e
n
n
=
0
F(S)=\min_{i=0\cdots n-1}F(S-c_i)+1\quad subject \ to \ S-c_i \ge 0 \\ F(S)=0, when \; S=0 \\ F(S)=-1,when \; n=0
F(S)=i=0⋯n−1minF(S−ci)+1subject to S−ci≥0F(S)=0,whenS=0F(S)=−1,whenn=0
动态规划
定义
F
(
i
)
F(i)
F(i)为组成金额
i
i
i所需要最小硬币数量,存在如下状态转移方程。
F
(
i
)
=
min
j
=
0
⋯
n
−
1
F
(
i
−
c
j
)
+
1
F(i)=\min _{j=0\cdots n-1} F(i-c_j) +1
F(i)=j=0⋯n−1minF(i−cj)+1
AC代码
递归搜索
class Solution {
public static int coinChange(int[] coins, int amount) {
int res=dp(coins,amount);
return res>=0x3f3f3f3f+1?-1:res;
}
public static int dp(int[] coins, int rem) {
if (rem < 0) // 状态不可达,返回-1
return -1;
else if (rem == 0) // 初始状态为0
return 0;
else {
int min = 0x3f3f3f3f;
// 搜索达到当前状态,所需要的最小硬币数
for (int coin : coins) {
int res = dp(coins, rem - coin);
// 如果子状态不可达,保持不变
min = res < 0 ? min : Math.min(res, min);
}
// 子状态加1,到达当前状态
return min + 1;
}
}
}
记忆化搜索
class Solution {
public static int coinChange(int[] coins, int amount) {
int res = dp(coins, amount, new int[amount + 1]);
return res >= 0x3f3f3f3f + 1 ? -1 : res;
}
public static int dp(int[] coins, int rem, int[] count) {
if (rem < 0)
return -1;
else if (rem == 0)
return 0;
else if (count[rem] != 0)
return count[rem]; // 记忆化搜索
else {
int min = 0x3f3f3f3f;
for (int coin : coins) {
int res = dp(coins, rem - coin, count);
min = res < 0 ? min : Math.min(res, min);
}
return count[rem]=min+1; // 记忆化搜索
}
}
}
动态规划
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp=new int[amount+1];
for(int i=0;i<amount+1;i++)
dp[i]=0x3f3f3f3f;
dp[0]=0;
for(int i=1;i<=amount;i++){
for(int j=0;j<coins.length;j++){
if(i-coins[j]>=0){
dp[i]=Math.min(dp[i-coins[j]]+1, dp[i]);
}
}
}
if(dp[amount]!=0x3f3f3f3f)
return dp[amount];
return -1;
}
public static void main(String[] args) {
Solution solution=new Solution();
int []coins=new int[]{1,2,5};
int amount=11;
System.out.println(solution.coinChange(coins, amount));
}
}