class Solution { /** Recursion */ public int coinChange(int[] coins, int amount) { int n = coins.length; int ans = findMinCoins(coins, amount, n); if(ans == Integer.MAX_VALUE-1) return -1; return ans; } public int findMinCoins(int[] coins, int amount, int n) { // base condition: No coins left // At this point, if amount > 0 (positive), we cannot form the remaining amount, because there are no coins left to use. // Returning 0 here would mean 0 coins are needed, which is incorrect, because we cannot form the positive amount with no coins. if(n == 0) return Integer.MAX_VALUE-1; // 0 coins needed to make amount as 0 if(amount == 0) return 0; if(coins[n-1] <= amount) { // we can pick same coin multiple times int pick = 1 + findMinCoins(coins, amount-coins[n-1], n); int notPick = findMinCoins(coins, amount, n-1); return Math.min(pick, notPick); } return findMinCoins(coins, amount, n-1); } /** Memoization */ public int coinChange(int[] coins, int amount) { int n = coins.length; int[][] t = new int[n+1][amount+1]; // when we have coins, but amount is always 0, so 0 coins needed to make amount as 0 for(int i=0; i 0 for(int j=0; j 0 (positive), we cannot form the remaining amount, because there are no coins left to use. // Returning 0 here would mean 0 coins are needed, which is incorrect, because we cannot form the positive amount with no coins. if(n == 0) return Integer.MAX_VALUE-1; // 0 coins needed to make amount as 0 if(amount == 0) return 0; if(t[n][amount] != Integer.MAX_VALUE - 1) return t[n][amount]; if(coins[n-1] <= amount) { // we can pick same coin multiple times int pick = 1 + findMinCoins(coins, amount-coins[n-1], n, t); int notPick = findMinCoins(coins, amount, n-1, t); t[n][amount] = Math.min(pick, notPick); return t[n][amount]; } t[n][amount] = findMinCoins(coins, amount, n-1, t); return t[n][amount]; } /** Top-down approach */ public int coinChange(int[] coins, int amount) { int n = coins.length; int[][] t = new int[n+1][amount+1]; for(int i=0; i