问题
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