public int coinChange(int[] coins, int amount) {
//Handle edge cases
if(amount == 0) return 0;
if(coins.length == 0) return -1;
int[][] matrix = new int[coins.length][amount];
/*******************************
* 1 2 3 4 5 ... amount *
* COIN 1 FIRST FILLED PART *
* COIN 2 *
* COIN 3 *
* ... *
* COIN N *
*******************************/
/************ NOTE ****************
* Each cell in matrix is read as:*
* *
* MINIMUM NUMBER OF COINS TO GET *
* AMOUNT J USING I COINS *
**********************************/
Arrays.sort(coins);
//fill FIRST FILLED
int firstCoin = coins[0];
for(int amountNumber = 1; amountNumber <= amount; amountNumber++){
if(amountNumber % firstCoin == 0){
matrix[0][amountNumber-1] = amountNumber/firstCoin;
}else{
matrix[0][amountNumber-1] = 0;
}
}
for(int indexCoin = 1; indexCoin < coins.length; indexCoin++){//COINS START IN SECOND COIN!!!(because of first filled)
for(int amountNumber = 1; amountNumber <= amount; amountNumber++){//in range [1, amount]
int coinEntered = coins[indexCoin];
if(coinEntered == amountNumber) {//if our coin matches exactly the amount we look for;
matrix[indexCoin][amountNumber-1] = 1;
continue;
}
if(coinEntered > amountNumber){//our coin is useless for the amount considered
int minimumNotIncludingEnteredCoin = matrix[indexCoin-1][amountNumber-1];//look how many coins it was needed to get before coinEntered was used
matrix[indexCoin][amountNumber-1] = minimumNotIncludingEnteredCoin;
continue;
}
int dif = amountNumber - coinEntered;
//we lookup the minimum number of coins using coin up to indexCoin (inclusive)
int minimumCoinsToGetDif = matrix[indexCoin][dif-1];
if(minimumCoinsToGetDif == 0){//no ways to get it
//take older result from not using coinEntered
int minimumNotIncludingEnteredCoin = matrix[indexCoin-1][amountNumber-1];//look how many coins it was needed to get before coinEntered was used
matrix[indexCoin][amountNumber-1] = minimumNotIncludingEnteredCoin;
}else{//there is a way to get it in minimumCoinsToGetDif times
if(matrix[indexCoin-1][amountNumber-1] == 0){
matrix[indexCoin][amountNumber-1] = minimumCoinsToGetDif+1;
continue;
}
int minimumNotIncludingEnteredCoin = matrix[indexCoin-1][amountNumber-1];//look how many coins it was needed to get before coinEntered was used
int coinsUsedUsingCoinEnteredAndDif = minimumCoinsToGetDif + 1;
if(coinsUsedUsingCoinEnteredAndDif < minimumNotIncludingEnteredCoin){
matrix[indexCoin][amountNumber-1] = coinsUsedUsingCoinEnteredAndDif;
}else{
matrix[indexCoin][amountNumber-1] = minimumNotIncludingEnteredCoin;
}
}
}
}
int lastElementInMatrix = matrix[coins.length-1][amount-1];//element in bottom right corner
if(lastElementInMatrix == 0) return -1;
return lastElementInMatrix;
}