LeetCode Top 100 Liked Questions 322. Coin Change (Java版; Medium)
题目描述
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:
Input: coins = [1, 2, 5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3
Output: -1
Note:
You may assume that you have an infinite number of each kind of coin
class Solution {
public int coinChange ( int [ ] coins, int amount) {
if ( coins. length== 0 ) {
return - 1 ;
}
int [ ] dp = new int [ amount+ 1 ] ;
int n = dp. length;
Arrays. fill ( dp, - 1 ) ;
dp[ 0 ] = 0 ;
for ( int i= 1 ; i< n; i++ ) {
for ( int c : coins) {
if ( i- c>= 0 && dp[ i- c] != - 1 ) {
if ( dp[ i] == - 1 ) {
dp[ i] = dp[ i- c] + 1 ;
} else {
dp[ i] = Math. min ( dp[ i] , dp[ i- c] + 1 ) ;
}
}
}
}
return dp[ n- 1 ] ;
}
}
第二次做; 暴力递归改动态规划
class Solution {
public int coinChange ( int [ ] coins, int amount) {
if ( coins== null || coins. length== 0 )
return - 1 ;
int [ ] dp = new int [ amount+ 1 ] ;
Arrays. fill ( dp, Integer. MAX_VALUE) ;
dp[ 0 ] = 0 ;
for ( int i= 1 ; i<= amount; i++ ) {
for ( int coin : coins) {
if ( i< coin)
continue ;
if ( dp[ i- coin] == Integer. MAX_VALUE)
continue ;
dp[ i] = Math. min ( dp[ i] , dp[ i- coin] + 1 ) ;
}
}
return dp[ amount] == Integer. MAX_VALUE? - 1 : dp[ amount] ;
}
}
第一次做; 暴力递归改成动态规划; 要注意很多细节的处理, 尤其是初始化!
import java. util. Arrays;
class Solution {
public int coinChange ( int [ ] coins, int amount) {
if ( coins== null || coins. length== 0 || amount< 0 )
return - 1 ;
Arrays. sort ( coins) ;
int [ ] dp = new int [ amount+ 1 ] ;
Arrays. fill ( dp, Integer. MAX_VALUE) ;
dp[ 0 ] = 0 ;
int count= 0 ;
for ( int i= 1 ; i<= amount; i++ ) {
for ( int j= 0 ; j< coins. length; j++ ) {
if ( i< coins[ j] )
break ;
if ( dp[ i- coins[ j] ] == Integer. MAX_VALUE)
continue ;
dp[ i] = Math. min ( dp[ i] , dp[ i- coins[ j] ] + 1 ) ;
}
}
return dp[ amount] == Integer. MAX_VALUE? - 1 : dp[ amount] ;
}
}
第一次做; 暴力递归优化, 使用memo数组, 取消了count参数, 从而让count表示当前rest的结果; 初始化真重要; 而且我现在知道了为什么没能把LC279改成动态规划, 因为我对可变参数的定义不明确, 更准确地说我没有把可变参数和返回的结果区分开, 我把结果也当做递归函数的参数并误以为结果也是可变参数, 所以当时就感觉结果这个变量没有范围啊? 现在才明确过来. 这道题的暴力递归版本我也把结果当做递归函数的参数了, 之后再写的暴力递归的时候, 试着不把结果写在递归函数参数中, 把结果写在递归函数参数中的缺点是: 不能使用memo数组优化暴力递归, memo索引的含义和结果不匹配; 大局意识: 要掌握流程的框架, “到这里已经计算完了凑成rest的所有可能”. 很多经验需要靠刷题去理解体会
import java. util. Arrays;
class Solution {
public int coinChange ( int [ ] coins, int amount) {
if ( coins== null || coins. length== 0 || amount< 0 )
return - 1 ;
Arrays. sort ( coins) ;
int [ ] memo = new int [ amount+ 1 ] ;
Arrays. fill ( memo, Integer. MAX_VALUE) ;
int res = core ( coins, memo, amount) ;
return res== Integer. MAX_VALUE? - 1 : res;
}
public int core ( int [ ] coins, int [ ] memo, int rest) {
if ( rest == 0 )
return 0 ;
if ( memo[ rest] != Integer. MAX_VALUE)
return memo[ rest] ;
int ans = Integer. MAX_VALUE;
for ( int i= 0 ; i< coins. length; i++ ) {
if ( coins[ i] > rest)
break ;
int curr = core ( coins, memo, rest- coins[ i] ) ;
if ( curr== - 1 )
continue ;
ans = Math. min ( ans, curr + 1 ) ;
}
memo[ rest] = ans== Integer. MAX_VALUE? - 1 : ans;
return memo[ rest] ;
}
}
暴力递归; 超时77/182; 核心: 不要把题目的最终结果作为递归函数的参数, 而是要作为递归函数的返回值
class Solution {
public int coinChange ( int [ ] coins, int amount) {
if ( coins== null || coins. length== 0 )
return - 1 ;
Arrays. sort ( coins) ;
int res = core ( coins, coins. length- 1 , amount) ;
return res;
}
private int core ( int [ ] coins, int index, int amount) {
if ( amount== 0 )
return 0 ;
if ( amount< 0 )
return - 1 ;
int res = Integer. MAX_VALUE;
for ( int i= index; i>= 0 ; i-- ) {
int cur = core ( coins, i, amount- coins[ i] ) ;
if ( cur== - 1 )
continue ;
res = Math. min ( res, cur+ 1 ) ;
}
return res== Integer. MAX_VALUE? - 1 : res;
}
}
第一次做;暴力递归,超时15/182; 这个暴力递归写的非常不好, 最不好的一点就是: 把最终结果作为递归函数的参数, 不要这么写!
import java. util. Arrays;
class Solution {
public int coinChange ( int [ ] coins, int amount) {
if ( coins== null || coins. length== 0 || amount < 0 )
return - 1 ;
Arrays. sort ( coins) ;
int res = core ( coins, amount, 0 ) ;
return res== Integer. MAX_VALUE? - 1 : res;
}
public int core ( int [ ] coins, int rest, int count) {
if ( rest== 0 )
return count;
int ans = Integer. MAX_VALUE;
int n = coins. length;
for ( int i= n- 1 ; i>= 0 ; i-- ) {
if ( coins[ i] > rest)
continue ;
int curr = core ( coins, rest- coins[ i] , count+ 1 ) ;
ans = Math. min ( ans, curr) ;
}
return ans;
}
}
leetcode上的最优解: 递归+memo
public class Solution {
public int coinChange ( int [ ] coins, int amount) {
if ( amount< 1 ) return 0 ;
return helper ( coins, amount, new int [ amount] ) ;
}
private int helper ( int [ ] coins, int rem, int [ ] count) {
if ( rem< 0 ) return - 1 ;
if ( rem== 0 ) return 0 ;
if ( count[ rem- 1 ] != 0 ) return count[ rem- 1 ] ;
int min = Integer. MAX_VALUE;
for ( int coin : coins) {
int res = helper ( coins, rem- coin, count) ;
if ( res>= 0 && res < min)
min = 1 + res;
}
count[ rem- 1 ] = ( min== Integer. MAX_VALUE) ? - 1 : min;
return count[ rem- 1 ] ;
}
}