Data Structure & Algorithm
JS_Cash Register
Alledy
2019. 4. 6. 23:01
문제
price는 가격이고, cash는 손님이 지불한 돈, cid는 현재 남아있는 잔고이다. cid의 예시는 다음과 같다.
// Example cash-in-drawer array: // [["PENNY", 1.01], // ["NICKEL", 2.05], // ["DIME", 3.1], // ["QUARTER", 4.25], // ["ONE", 90], // ["FIVE", 55], // ["TEN", 20], // ["TWENTY", 60], // ["ONE HUNDRED", 100]]
돈의 단위는 다음과 같다.
Currency Unit Amount Penny $0.01 (PENNY) Nickel $0.05 (NICKEL) Dime $0.1 (DIME) Quarter $0.25 (QUARTER) Dollar $1 (DOLLAR) Five Dollars $5 (FIVE) Ten Dollars $10 (TEN) Twenty Dollars $20 (TWENTY) One-hundred Dollars $100 (ONE HUNDRED) - 만약 잔고가 부족하거나, 가지고 있는 돈의 단위로는 온전하게 거스름돈을 거슬러 줄 수 없다면 status는 'INSUFFICIENT_FUNDS'를 나타내고, change는 빈 어레이를 리턴한다.
- 잔고가 있고 온전히 거슬러줄 수 있으면 status는 'OPEN'을 나타내고 change는 거스름돈을 배열로 나타내어 리턴한다. (큰 돈의 단위부터)
- 거스름돈과 잔고가 완전히 일치할 경우 status는 'CLOSED'를 나타내고 change는 그 거스름돈을 배열로 나타낸다.
// 예시 // 잔고가 부족한 경우 checkCashRegister(19.5, 20, [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]) should return {status: "INSUFFICIENT_FUNDS", change: []}. // 잔고와 거스름돈이 같은 경우 checkCashRegister(19.5, 20, [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]) should return {status: "CLOSED", change: [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]}. // 잔고가 있으나 돈의 단위가 안 맞아 온전히 거슬러 줄 수 없는 경우 checkCashRegister(19.5, 20, [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 1], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]) should return {status: "INSUFFICIENT_FUNDS", change: []}. // 잔고도 있고 온전히 거슬러 줄 수 있는 경우 1 checkCashRegister(19.5, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]) should return {status: "OPEN", change: [["QUARTER", 0.5]]}. // 잔고도 있고 온전히 거슬러 줄 수 있는 경우 2 checkCashRegister(3.26, 100, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]) should return {status: "OPEN", change: [["TWENTY", 60], ["TEN", 20], ["FIVE", 15], ["ONE", 1], ["QUARTER", 0.5], ["DIME", 0.2], ["PENNY", 0.04]]}.
- 내가 푼 답
function checkCashRegister(price, cash, cid) {
var result = {status: '', change: []};
var total = 0;
var change = cash - price;
var currency = [0.01, 0.05, 0.1, 0.25, 1, 5, 10, 20, 100];
for(var i of cid) {
total = total + i[1];
}
if(change > total) {
result.status = 'INSUFFICIENT_FUNDS';
return result;
}
if(change === total) {
result.status = 'CLOSED';
result. change = cid;
return result;
}
if(change < total) {
for(var j = currency.length - 1 ; j >=0 ; j--) {
if(change > currency[j] && cid[j][1] !== 0) {
var unit = cid[j][1] / currency[j];
var n = 0;
while(unit > 0 && change - currency[j] >= 0) {
change = (change - currency[j]).toFixed(2)
unit --;
n++;
}
result.change.push([cid[j][0], n * currency[j]])
}
}
if(change == 0) {
result.status = 'OPEN';
return result;
} else {
result.status = 'INSUFFICIENT_FUNDS';
result.change = [];
return result;
}
}
}
덧셈이 제대로 안 되는 js 특성 때문에 toFixed를 사용했다. 밑의 솔루션은 Math.round를 사용했다.
- Solution
var denom = [
{ name: 'ONE HUNDRED', val: 100.00},
{ name: 'TWENTY', val: 20.00},
{ name: 'TEN', val: 10.00},
{ name: 'FIVE', val: 5.00},
{ name: 'ONE', val: 1.00},
{ name: 'QUARTER', val: 0.25},
{ name: 'DIME', val: 0.10},
{ name: 'NICKEL', val: 0.05},
{ name: 'PENNY', val: 0.01}
];
function checkCashRegister(price, cash, cid) {
var output = { status: null, change: [] };
var change = cash - price;
// Transform CID array into drawer object
var register = cid.reduce(function(acc, curr) {
acc.total += curr[1];
acc[curr[0]] = curr[1];
return acc;
}, { total: 0 });
// Handle exact change
if (register.total === change) {
output.status = 'CLOSED';
output.change = cid;
return output;
}
// Handle obvious insufficient funds
if (register.total < change) {
output.status = 'INSUFFICIENT_FUNDS';
return output;
}
// Loop through the denomination array
var change_arr = denom.reduce(function(acc, curr) {
var value = 0;
// While there is still money of this type in the drawer
// And while the denomination is larger than the change remaining
while (register[curr.name] > 0 && change >= curr.val) {
change -= curr.val;
register[curr.name] -= curr.val;
value += curr.val;
// Round change to the nearest hundreth deals with precision errors
change = Math.round(change * 100) / 100;
}
// Add this denomination to the output only if any was used.
if (value > 0) {
acc.push([ curr.name, value ]);
}
return acc; // Return the current change_arr
}, []); // Initial value of empty array for reduce
// If there are no elements in change_arr or we have leftover change, return
// the string "Insufficient Funds"
if (change_arr.length < 1 || change > 0) {
output.status = 'INSUFFICIENT_FUNDS';
return output;
}
// Here is your change, ma'am.
output.status = 'OPEN';
output.change = change_arr;
return output;
}
reduce를 쓰니까 더 깔끔해보인다.