You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FreeCodeCamp收银抽屉函数checkCashRegister()找零逻辑问题求助

搞定checkCashRegister里多次扣大面额的问题

我之前帮不少人解决过FreeCodeCamp这个收银抽屉的挑战,你遇到的多次扣除大面额(比如Twenty美元)的问题,本质是没做好循环复用单一面额的逻辑——毕竟找零的时候可能需要好几张二十,总不能只扣一次就停对吧?

先给你理清楚核心思路,再上修正后的代码:

关键前提要理清

  1. 先把每个面额和它的数值对应好,而且要从大到小排序,收银都是先拿大面额凑的对吧?
  2. 处理浮点数精度!直接用0.01、0.25这种计算容易出bug,建议每次计算后用toFixed(2)转成两位小数,或者干脆乘以100转成整数计算(我下面用的是前者)
  3. 先判断三种基础情况:收银机总钱不够找零、刚好够(直接返回全部现金)、够但需要凑找零

核心修正:循环扣减同面额

之前你可能是单次判断能不能扣当前面额,但实际上要一直扣,直到这个面额的钱不够扣,或者找零已经凑够了。比如要找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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:47:42