问题描述
我正在尝试解决硬币找零问题(https://leetcode.com/problems/coin-change),并提出了以下递归方法:
class Solution {
public int coinChange(int[] coins,int amount) {
int[] min = new int[1];
min[0] = Integer.MAX_VALUE;
recur(coins,amount,min,0);
min[0] = min[0]==Integer.MAX_VALUE?-1:min[0];
return min[0];
}
private void recur(int[] coins,int amount,int[] min,int coinsUsed){
if(amount==0){
min[0] = Math.min(min[0],coinsUsed);
return;
}
if(amount<0){
return;
}
for(int i=0;i<coins.length;++i){
recur(coins,amount-coins[i],coinsUsed+1);
}
}
}
当前时间复杂度为O((coins.length)^ n)。如何添加便笺来改善这一点?
解决方法
通常,自上而下的记忆会变得有些复杂。一种简单的方法是使用二维数组并自底向上解决问题。假设您有n个面额(从1到n的索引)且总和为S。令T [n] [S]是您需要加总S的最小硬币数量,而v [n]是硬币n的值。
使用硬币n或不使用硬币n都有两种选择。如果你不这样做 那么T [n] [S] = T [n-1] [S]。如果这样做,则T [n] [S] = 1 + T [n] [S-v [n]],因为您不知道哪个是 那就好了
T [n] [S] = min(T [n-1] [S],1 + T [n] [S-v [n]])。 对于所有n都是如此,因此我们得到了递归公式。
T [i] [s] = min(T [i-1] [s],1 + T [i] [s-v [i]])
现在考虑边界条件
- 如果i = 1,则所有0的T [1] [s] = s
- T [i] [0] = 0表示1
int x,y;
int T[n+1][S+1];
//initialization
for(y=0;y<=S;y++)
T[1][y]=y;
for(x=0;x<=n;x++)
T[x][0]=0;
//solution
for(x=2;x<=n;x++){
for(y=0;y<=S;y++){
if (v[x]>= y )
T[x][y]=min(T[x-1][y],1+T[x][y-v[x]];
else
T[x][y]=T[x-1][y];
}
}