问题
Today I come to your aid in favor of optimizing some code!
I was asked to solve a problem on a test a few weeks ago, and came up with this non-optimal solution since I'm beggining to learn Javascript.
I wonder if there's a way (of course there is) to make this better.
Here's the situation:
"I am a particular kind person who has an infinite ammount of $2, $5 and $10 dollar bills, and I'm willing to change cash for anyone who wants it, BUT in the most efficient way, with the minimum ammount of bills."
Since I had to return an object with the number of bills (or null in case of less than $2), I gave the following solution:
function giveChange(change){    
var two = 0;
var five = 0;
var ten = 0;
var changeToGo = change;
while(changeToGo >= 11){
    changeToGo -=10;
    ten+=1;
}
while(changeToGo >=7 && changeToGo <=11){
    changeToGo-=5;
    five+=1;
}
while(changeToGo >=2 && changeToGo <=6 ){
    if(changeToGo == 5){
        changeToGo -=5;
        five+=1;
}
    else{
        changeToGo -= 2;
        two+=1;
    }
}
if (change < 2){
    return null;
}
return {
    two: two,
    five: five,
    ten: ten
};
}
I think there must be a clever and more elegant solution (probably with mod% or something), but that monstrosity was what I was able to pull off at the time hahaha.
Any thoughts?
回答1:
Edit: Removed he initial answer, as it was based on a misconception about the requirements.
Ok, then let's turn that around, first let's determine how many $2 bills I'll have to hand out to get to a number that's divisible by $5 bills. So for now I only care about the rests < $5 for to calculate the $2 bills.
The generic idea is, If I have a value where change%5 is 2, like $12 or $17 or $22, ... I hand out one $2 bill and I can divide the rest by 5. 
For values like $14, $19, ... it's two $2 bills, for $11, $16, ... I subtract $6, and for $13, $18, ... it's $8
With that I have a static table of how many $2 bills I'd have to hand out, for every change % 5; no loops or so needed, just a simple lookup.
function giveChange(change){
  const two = change < 4? change>>1: [0,3,1,4,2][Math.floor(change) % 5],
    rest = change - two*2;
  return { 
    two,
    five: Math.floor((rest%10)/5), 
    ten: Math.floor(rest/10), 
  };
}
Care to explain again what this does? "change>>1" and "[0,3,1,4,2][Math.floor(change) % 5];" ?
change >> 1 is here just a shorthand for Math.floor(change/2) and deals mostly with the special cases giveChange(1) and giveChange(3); They are not interchangable, but for the range 0..4 (where I use it) they produce the same result.
let two = [0,3,1,4,2][change % 5];
//does 
let two;
if(change%5 === 0) two = 0;
if(change%5 === 1) two = 3;
if(change%5 === 2) two = 1;
if(change%5 === 3) two = 4;
if(change%5 === 4) two = 2;
And Math.floor(change) % 5 is just in case that you'll use this with floats, like giveChange(25.90)
But maybe an example explains it better
for(let change=4; change<50; ++change){
  let two = [0,3,1,4,2][change%5];
  console.log("change: %i, two: %i, rest: %i", change, two, change - two*2);
}
.as-console-wrapper{top:0;max-height:100%!important}
you see how two always always has the same 5 values in the same order, and how the rest now is divisible by 5 and or 10.
That's what this code does, it looks up the Array [0,3,1,4,2], how many $2 bills it needs use for any given change, so that the rest is divisible by 5.
回答2:
The idea: when the amount is odd, add a five dollar bill. Then add two dollar bills until the remaining amount is a multiple of ten.
function giveChange(amount) {
    var ch = { two:0, five:0, ten:0 };
    if ( amount < 2 || amount == 3 ) return;
    if ( amount % 2 ) {
        amount -= 5;
        ch.five = 1;
    }   
    
    while ( amount % 10 ) {
        amount -= 2;
        ch.two ++;
    }
    ch.ten = amount/10;
    return ch;
}
console.log(giveChange(12));
console.log(giveChange(27));
console.log(giveChange(33));
You can also skip the while loop if you use Math.floor:
function giveChange(amount) {
    var ch = { two:0, five:0, ten:0 };
    if ( amount < 2 || amount == 3 ) return;
    if ( amount % 2 ) {
        amount -= 5;
        ch.five ++;
    }
  
    ch.ten = Math.floor(amount/10);
    ch.two = (amount % 10)/2;
    return ch;
}
console.log(giveChange(12));
console.log(giveChange(27));
console.log(giveChange(33));
回答3:
You could take a combination algorithm and return the denominators in an array
function combine(array, sum) {
    function c(left, right, sum) {
        if (!sum) {
            result = right;
            return true;
        }
        return left.some(function (a, i, aa) {
            return a <= sum && c(aa.slice(i + (a > sum - a)), right.concat(a), sum - a);
        });
    }
    var result = [];
    c(array.sort(function (a, b) { return b - a; }), [], sum);
    return result;
}
function giveChange(change) {
    return combine([10, 5, 2], change);
}
console.log(giveChange(7));
console.log(giveChange(13));
console.log(giveChange(23));
回答4:
here is my Solution, tested it and works fine
function caisse(cash){
two =0;
five =0;
ten = 0;
if (cash>10){
rendu = cash%10;
ten = Math.floor(cash/10);
}
if (rendu%2===0){
  two = rendu/2
}
  if (rendu%2==1 && rendu>=5)
{
  five = 1
two = (rendu-5)/2; 
}
  else if (rendu%2==1 && rendu<5){
    two=Math.floor(rendu/2);
}
return {"two :": two, "five :": five, "ten : ": ten};
}
    来源:https://stackoverflow.com/questions/48914689/change-cash-function-optimization-javascript