Javascript Coin changing / Change making algorithm

So I've been trying to create a program in Javascript/jQuery that splits an amount of money into the smallest amount of dollar bills. So far the program only works with one bill, and I'm not too sure how to implement the rest and need a push in the right direction here.

var bills = [5, 10, 20, 50, 100];

while(money > 0){ // Keep deviding
    for(var i=0; i < bills.length; i++){
        if(money < bills[i])
            return "You need a $" + bills[i] + " bill to pay for your item.";
    }
}

If I run this with money = 89; it will return 100 because that's the closest bill that can pay for $89, but I want it to return 50 + 20 + 20 so it will work with money = *anything*.

EDIT: After comments I've now come so far:

while(money > 0){ // Keep deviding
    for(var i=bills.length-1; i >= 0; i--){
        if(money > bills[i] || i == 0){
            stringToReturn += " + $" + bills[i];
            money -= bills[i];
            break;
        }
    }
}

Answers:

Answer

As stated in the comments, it might be a variant of the Knapsack problem.

Edit : it's actually known as coin changing or change making problem.

If I understood well, you want a minimal solution to this inequation :

a1x1 + a2x2 + ... + anxn >= b

The sum must be as close as possible to b with as few bills as possible.

Brute force recursive solution

  • Get all possible combination of bills that answer your inequation
  • Find the ones which sum is the closest to the solution
  • Find the solution using the less bills

//Available bills and money required
//var availableBills = [2, 5, 8, 16]; var money = 22;
//var availableBills = [13, 17, 30, 70, 158]; var money = 200;
var availableBills = [5, 17, 29, 70, 158];
var money = 200;
//var availableBills = [5, 10, 178]; var money = 20;
//var availableBills = [5, 20, 30, 70, 158]; var money = 157;
//var availableBills = [1, 5, 10]; var money = 97;

//Get all the money in a wallet
function getWalletSum(wallet) {
  var sum = 0;
  for (var bill in wallet) {
    sum += wallet[bill] * bill;
  }
  return sum;
}

//Copy a wallet without empty values
function copyWallet(wallet) {
  var newWallet = {};
  for (var bill in wallet) {
    if (wallet[bill] != 0) {
      newWallet[bill] = wallet[bill];
    }
  }
  return newWallet;
}

//Merge two wallets without empty values
function mergeWallets(wallet1, wallet2) {
  var mergedWallet = copyWallet(wallet1);
  for (var bill in wallet2) {
    if (wallet2[bill] != 0) {
      mergedWallet[bill] = wallet2[bill];
    }
  }
  return mergedWallet;
}

var cycles = 0;
var loops = 0;

//Get possible wallets
//Return wallets having sum >= money
function getPossibleWallets(money, startingBills) {
  cycles++;
  var possibleWallets = [];
  var wallet = {};
  var bills = startingBills.slice();
  var maxBill = bills.pop();
  wallet[maxBill] = Math.ceil(money / maxBill);
  while (wallet[maxBill] >= 0) {
    loops++;
    var walletSum = getWalletSum(wallet);
    if (walletSum == money) {
      possibleWallets.push(copyWallet(wallet));
      return possibleWallets;
    }
    if (walletSum > money) {
      possibleWallets.push(copyWallet(wallet));
    } else {
      if (bills.length > 0) {
        var remaining = money - getWalletSum(wallet);
        var remainingWallets = getPossibleWallets(remaining, bills);
        for (var i = 0; i < remainingWallets.length; i++) {
          var mergedWallet = mergeWallets(wallet, remainingWallets[i]);
          possibleWallets.push(mergedWallet);
          if (getWalletSum(mergedWallet) == money) {
            return possibleWallets;
          }
        };
      }
    }
    wallet[maxBill] = wallet[maxBill] - 1;
  }
  return possibleWallets;
}

//Get smallest possible wallet
// > Wallet sum >= money
// > Wallet sum is as close as possible to money
// > Wallet is as small as possible (less bills)
function getSmallestSufficientWallet(money, startingBills) {
  var possibleWallets = getPossibleWallets(money, startingBills);
  console.log(possibleWallets);
  var minWallet = possibleWallets[0];
  for (var i = 0; i < possibleWallets.length; i++) {
    var possibleWallet = possibleWallets[i];
    var possibleWalletSum = getWalletSum(possibleWallet);
    if (possibleWalletSum == money) {
      return possibleWallet;
    }
    if (possibleWalletSum < getWalletSum(minWallet) && possibleWalletSum >= money) {
      minWallet = possibleWallet;
    }
  }
  return minWallet;
}

var wallet = getSmallestSufficientWallet(money, availableBills);
console.log('cycles = ' + cycles);
console.log('loops = ' + loops);

//Array of bills to string
function billsToString(billsArray) {
  return billsArray.join('$, ') + '$';
}

//Wallet to string
function walletToString(wallet) {
  var result = [];
  for (bill in wallet) {
    result.push(wallet[bill] + ' * ' + bill + '$');
  }
  return result.join(' + ');
}

//Print
var questionString = '<div>Money : ' + money + '$</div>';
questionString += '<div>Available : ' + billsToString(availableBills) + '</div>';
document.getElementById('question').innerHTML = questionString;
document.getElementById('bills').innerHTML = 'Wallet : ' + walletToString(wallet);
document.getElementById('sum').innerHTML =
  '<div>Total = ' + getWalletSum(wallet) + '</div>' +
  '<div>Difference = ' + (getWalletSum(wallet) - money) + '</div>';
<div id="question"></div>
<div id="bills"></div>
<div id="sum"></div>

Answer
var bills = [5, 10, 20, 50, 100];
var money = mod(89);

function mod(num){
    if (num % 5 === 0){
        return num;
    }else{
        return num + 5 - num % 5
    }
}

function foo(num){
    var index = bills.length - 1;
    var splits = [];
    while (money >= bills[0]){
        if (money >= bills[index]){
           money -= bills[index];
           splits.push(bills[index]);
        }else{
            index--;
        }
    }
    return splits;
}

console.log(foo(money));

edited jsfiddle

Answer

In a more compacted way:

function moneyChanger(money, bills){
    if (bills[0] < bills[1]) bills.reverse();
    const change = {};
    bills.map(b => {
       change[b] = Math.floor(money/b);
       money -= b*change[b];
    }) 
    return change
}

...

var change = moneyChanger(2995,[5,10,20,50,100,200,500])

The result for this example:

{5:1, 10:0, 20:2, 50:1, 100:0, 200:2, 500:5}

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.