Javascript硬币更改/更改制作算法

时间:2015-02-10 17:02:21

标签: javascript algorithm

所以我一直在尝试用Javascript / jQuery创建一个程序,将一大笔钱分成最小的美元账单。到目前为止,该程序仅适用于一个账单,我不太确定如何实现其余的,并且需要在这里推进正确的方向。

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.";
    }
}

如果我使用money = 89;运行它,它将返回100,因为这是最接近可以支付89美元的账单,但我希望它返回50 + 20 + 20,因此它将与money = *anything*一起使用。

编辑:评论之后我现在到目前为止:

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;
        }
    }
}

3 个答案:

答案 0 :(得分:6)

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));

已编辑jsfiddle

答案 1 :(得分:2)

如评论中所述,它可能是背包问题的变体。

编辑:它实际上称为硬币更改或change making problem

如果我理解得很好,你需要一个解决这个不公平的最小解决方案:

a 1 x 1 + a 2 x 2 + ... + a n x n &gt; = b

总和必须尽可能接近b,尽可能少的账单。

强力递归解决方案

  • 获取应对不公平的所有可能的账单组合
  • 找出与解决方案最接近的那些
  • 使用少量账单找到解决方案

//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>

答案 2 :(得分:0)

以更紧凑的方式:

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])

此示例的结果:

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