update Jan 9,2018 21:16
LeetCodearrow-up-right
You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
Example 1:
Copy coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1) Example 2:
Copy coins = [2], amount = 3
return -1. Note:
You may assume that you have an infinite number of each kind of coin.
思路 1,dfs,combination sum (TLE):
首先想到直接用combination sum的方法求解,但是果然 TLE 了。思路是dfs分为 len(coins) 层,每层表示一种 coin。在每层中的分支表示使用当前 coin 不同次数,时间复杂度为 O([target amount / min(coins)]^len(coins)).
Java Code:
Copy class Solution {
public int coinChange ( int [] coins , int amount ) {
int ret = dfs ( coins , amount , 0 , 0 );
return ret == Integer . MAX_VALUE ? - 1 : ret ;
}
private int dfs ( int [] coins , long remainSum , int pos , int path ) {
if ( remainSum == 0 || pos == coins . length ) {
if ( remainSum == 0 ) return path ;
return Integer . MAX_VALUE ;
}
int minCount = Integer . MAX_VALUE ;
for ( int i = 0 ; i * ( long )( coins [ pos ]) <= remainSum ; ++ i ) {
int count = dfs ( coins , remainSum - i * coins [ pos ], pos + 1 , path + i );
minCount = Math . min ( minCount , count );
}
return minCount ;
}
} 思路 2,优化,memorized search (AC):
接下来考虑之前之所以 TLE 了,是因为有很多重复情况被重复考虑,例如:
根据这种思路,我们可以用一个 HashMap<remain, coinNum> 来做记忆化搜索。但是要注意,如果按照之前在 DFS notes 中缩写的那种写法(即之前的dfs写法),因为每层除了remainSum之外,可选的coins也是不同的,所以不能直接使用。如果要用 HashMap 辅助,我们必须使用那种 naive 的每层分别考虑使用每个数的做法:
另外,在dfs的过程中,我们的dfs函数需要自下而上地返回每个remainSum的所需coin个数,而不是自上而下传入path,这样才能进行记忆化搜索。
Java Code:
思路 3,DP, bottom up( AC ):
首先我们可以有递推式:
没什么神奇的,直接用 O(amount * len(coins)) 时间从前到后递推直到得到 dp[amount],空间复杂度 O(amount);
Java Code:
思路 4: DP,top-down (AC)
仍然是前面的递推式,只是我们用recursion从上至下求解。
Java Code:
这道题目用dp做和用 memorized search 的时间复杂度其实是差不多的,因为问题的规模是 O(amount * len(coins))。用dfs直接做的话,因为会计算很多重复情况,会TLE。这也印证了那句话:求解的数量用dp,如果求解的空间则必须用dfs,因为即使两个问题的子问题相同,他们也是不同的两个解 。