diff --git a/Dynamic-Programming/CoinChange.js b/Dynamic-Programming/CoinChange.js index 7c7e6a8a6..df3183918 100644 --- a/Dynamic-Programming/CoinChange.js +++ b/Dynamic-Programming/CoinChange.js @@ -1,58 +1,21 @@ -function change (coins, amount) { +/** + * @params {Array} coins + * @params {Number} amount + */ +export const change = (coins, amount) => { + // Create and initialize the storage const combinations = new Array(amount + 1).fill(0) combinations[0] = 1 - + // Determine the direction of smallest sub-problem for (let i = 0; i < coins.length; i++) { - const coin = coins[i] - - for (let j = coin; j < amount + 1; j++) { - combinations[j] += combinations[j - coin] + // Travel and fill the combinations array + for (let j = coins[i]; j < combinations.length; j++) { + combinations[j] += combinations[j - coins[i]] } } return combinations[amount] } - -/** Coin-change combination using recursive approach along with Memoization - * @param {number} amount - * @param {number[]} coins - */ -const changeRecursive = (amount, coins) => { - const mem = new Map() - return coinChangeComb(amount, coins, 0, mem) -} -/** Coin-change combination using recursive approach along with Memoization - * @param {number} amount - * @param {number[]} coins - * @param {number} idx - * @param {Map} mem - */ - -const coinChangeComb = (amount, coins, idx, mem) => { - // Negative Base Case - if (amount < 0 || idx === coins.length) { - return 0 - } - // Positive Base Case - if (amount === 0) { - return 1 - } - - // Main Case - // Check if the recursive function call results is already memoized - if (mem.has(`${amount} - ${idx}`)) { - return mem.get(`${amount} - ${idx}`) - } - let res = 0 - // Consider the coin at index idx - res += coinChangeComb(amount - coins[idx], coins, idx, mem) - // Leave the coin at index idx - res += coinChangeComb(amount, coins, idx + 1, mem) - // Cache the intermediate result in mem - mem.set(`${amount} - ${idx}`, res) - return res -} - -function minimumCoins (coins, amount) { +function minimumCoins(coins, amount) { // minimumCoins[i] will store the minimum coins needed for amount i const minimumCoins = new Array(amount + 1).fill(0) @@ -77,28 +40,3 @@ function minimumCoins (coins, amount) { } return minimumCoins[amount] } - -function main () { - const amount = 12 - const coins = [2, 4, 5] - console.log( - 'Number of combinations of getting change for ' + - amount + - ' is: ' + - change(coins, amount) - ) - console.log( - 'Number of combinations of getting change for ' + - amount + - ' is: ' + - changeRecursive(coins, amount) - ) - console.log( - 'Minimum number of coins required for amount :' + - amount + - ' is: ' + - minimumCoins(coins, amount) - ) -} - -main() diff --git a/Dynamic-Programming/tests/CoinChange.test.js b/Dynamic-Programming/tests/CoinChange.test.js new file mode 100644 index 000000000..dc98c68c9 --- /dev/null +++ b/Dynamic-Programming/tests/CoinChange.test.js @@ -0,0 +1,37 @@ +import { change } from '../CoinChange' + +test('Base Case 1', () => { + const coins = [2, 3, 5] + const amount = 0 + expect(change(coins, amount)).toBe(1) +}) +test('Base Case 2', () => { + const coins = [] + const amount = 100 + expect(change(coins, amount)).toBe(0) +}) +test('Test Case 1', () => { + const coins = [2, 4, 5] + const amount = 12 + expect(change(coins, amount)).toBe(5) +}) +test('Test Case 2', () => { + const coins = [5, 2, 3, 7, 6, 1, 12, 11, 9, 15] + const amount = 45 + expect(change(coins, amount)).toBe(12372) +}) +test('Test Case 3', () => { + const coins = [2] + const amount = 3 + expect(change(coins, amount)).toBe(0) +}) +test('Test Case 4', () => { + const coins = [3, 5, 7, 8, 9, 10, 11] + const amount = 500 + expect(change(coins, amount)).toBe(35502874) +}) +test('Test Case 5', () => { + const coins = [10] + const amount = 10 + expect(change(coins, amount)).toBe(1) +})