FreeCodeCamp收银抽屉函数checkCashRegister()找零逻辑问题求助
搞定checkCashRegister里多次扣大面额的问题
我之前帮不少人解决过FreeCodeCamp这个收银抽屉的挑战,你遇到的多次扣除大面额(比如Twenty美元)的问题,本质是没做好循环复用单一面额的逻辑——毕竟找零的时候可能需要好几张二十,总不能只扣一次就停对吧?
先给你理清楚核心思路,再上修正后的代码:
关键前提要理清
- 先把每个面额和它的数值对应好,而且要从大到小排序,收银都是先拿大面额凑的对吧?
- 处理浮点数精度!直接用0.01、0.25这种计算容易出bug,建议每次计算后用
toFixed(2)转成两位小数,或者干脆乘以100转成整数计算(我下面用的是前者) - 先判断三种基础情况:收银机总钱不够找零、刚好够(直接返回全部现金)、够但需要凑找零
核心修正:循环扣减同面额
之前你可能是单次判断能不能扣当前面额,但实际上要一直扣,直到这个面额的钱不够扣,或者找零已经凑够了。比如要找60美元的二十,就得扣三次20,这时候while循环就派上用场了。
完整修正代码示例
function checkCashRegister(price, cash, cid) { // 定义面额:从大到小排序,方便优先用大面额凑找零 const denominations = [ ["ONE HUNDRED", 100.00], ["TWENTY", 20.00], ["TEN", 10.00], ["FIVE", 5.00], ["ONE", 1.00], ["QUARTER", 0.25], ["DIME", 0.10], ["NICKEL", 0.05], ["PENNY", 0.01] ]; // 计算总找零金额,处理精度 let changeDue = Number((cash - price).toFixed(2)); // 计算收银机内总现金 const totalCID = Number(cid.reduce((sum, item) => sum + item[1], 0).toFixed(2)); // 情况1:总钱不够找零 if (totalCID < changeDue) { return { status: "INSUFFICIENT_FUNDS", change: [] }; } // 情况2:刚好够,直接返回全部现金 if (totalCID === changeDue) { return { status: "CLOSED", change: cid }; } // 情况3:够找零,开始凑钱 const change = []; let remainingChange = changeDue; for (const [name, value] of denominations) { // 找到当前面额在cid里的可用金额 const available = cid.find(item => item[0] === name)[1]; let amountUsed = 0; // 核心:循环扣减当前面额,直到不够扣或者找零凑够 while (remainingChange >= value && available > amountUsed) { amountUsed += value; remainingChange = Number((remainingChange - value).toFixed(2)); } // 如果用了这个面额的钱,就加到找零数组里 if (amountUsed > 0) { change.push([name, amountUsed]); } } // 最后检查:如果还是没凑够全部找零(比如面额组合不对),返回不够 if (remainingChange > 0) { return { status: "INSUFFICIENT_FUNDS", change: [] }; } return { status: "OPEN", change: change }; } // 测试你给的示例 console.log(checkCashRegister(3.26, 100.00, [ ["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.10], ["QUARTER", 4.25], ["ONE", 90.00], ["FIVE", 55.00], ["TEN", 20.00], ["TWENTY", 60.00], ["ONE HUNDRED", 100.00] ])); // 应该返回:{ status: "OPEN", change: [["TWENTY", 60], ["TEN", 20], ["FIVE", 15], ["ONE", 1], ["QUARTER", 0.5], ["DIME", 0.2], ["PENNY", 0.04]] }
重点解释
- 用
while (remainingChange >= value && available > amountUsed)这个循环,就能实现多次扣同一个大面额,比如示例里的60美元二十,会循环三次,每次加20,直到把available的60用完 - 每次计算后用
Number((...).toFixed(2))处理精度,避免出现0.1+0.2=0.30000000000000004这种坑 - 最后一定要检查
remainingChange是否为0,比如收银机总钱够,但只有一堆1美元,要找20美元的话,就会凑不够,这时候得返回INSUFFICIENT_FUNDS
内容的提问来源于stack exchange,提问作者Merim
相关产品推荐
相关产品推荐

