class Solution {
/** Recursion */
public int count(int coins[], int sum) {
int n = coins.length;
return countCombinations(coins, sum, n);
}
public int countCombinations(int[] coins, int sum, int n)
{
// base condition: when sum becomes 0 then we found valid combination
if(sum == 0)
return 1;
// base condition: when we reach end of array, no valid combination found
if(n == 0)
return 0;
if(coins[n-1] <= sum)
{
// include the current coin into combination, and this coin can be used later too
int pick = countCombinations(coins, sum - coins[n-1], n);
// do not include the current coin into combination
int notPick = countCombinations(coins, sum, n-1);
return pick + notPick;
}
// when current coin has value greater than the required sum, skip the coin
return countCombinations(coins, sum, n-1);
}
/** Memoization */
public int count(int coins[], int sum) {
int n = coins.length;
int[][] t = new int[n+1][sum+1];
// when array size keeps on increasing but sum is 0, so we can have empty list
for(int i=0; i<n+1; i++)
{
}
// when array size is 0, but sum keeps on increasing so we cannot have combination
for(int j=0; j<n+1; j++)
{
}
return countCombinations(coins, sum, n, t);
}
public int countCombinations(int[] coins, int sum, int n, int[][] t)
{
// base condition: when sum becomes 0 then we found valid combination
if(sum == 0)
return 1;
// base condition: when we reach end of array, no valid combination found
if(n == 0)
return 0;
if(t[n][sum] != 0)
return t[n][sum];
if(coins[n-1] <= sum)
{
// include the current coin into combination, and this coin can be used later too
int pick = countCombinations(coins, sum - coins[n-1], n, t);
// do not include the current coin into combination
int notPick = countCombinations(coins, sum, n-1, t);
t[n][sum] = pick + notPick;
return t[n][sum];
}
// when current coin has value greater than the required sum, skip the coin
t[n][sum] = countCombinations(coins, sum, n-1, t);
return t[n][sum];
}
/** Top-down approach */
public int count(int coins[], int sum) {
int n = coins.length;
int[][] t = new int[n+1][sum+1];
for(int i=0; i<n+1; i++)
{
for(int j=0; j<sum+1; j++)
{
// when array is empty
if(i == 0)
t[i][j] = 0;
// when sum is 0
if(j == 0)
t[i][j] = 1;
}
}
for(int i=1; i<n+1; i++)
{
for(int j=1; j<sum+1; j++)
{
if(coins[i-1] <= j)
{
// include the current coin into combination, and this coin can be used later too
int pick = t[i][j - coins[i-1]];
// do not include the current coin into combination
int notPick = t[i-1][j];
t[i][j] = pick + notPick;
}
else
t[i][j] = t[i-1][j];
}
}
return t[n][sum];
}
}