题目重点:Refund 面经给 CREDIT→CREDIT_CARD→PAYPAL 与同方式按较新支付;核已有退款后分配,明确题目样例互相矛盾。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 每笔 payment 有 ID、方式、时间、原额和已有 refund 总额;当前可退额=max(0,paid−previousRefunded),不超过原支付额。
- 先按方式优先级,再按支付时间降序;同时间用稳定 ID/原输入序 tie-break,题目未定义。
- 若请求退款额大于所有剩余可退额,训练版返回不足额错误而不部分提交;题目未明确超额处理。
- 金额用整数最小单位,避免浮点误差;退款输出可拆为多笔 payment-linked 项。
解题路线
- 先汇总所有已有 refund,按 paymentId 校验不会超过 paid,并算 remaining;若总 remaining<目标,先拒绝且不修改状态。
- 把 remaining>0 的 payment 按 (方式序号,−timestamp,稳定ID) 排序,依序分配 min(目标剩余,该笔 remaining),只有一笔支付无法覆盖剩余请求时才进入下一笔。
- 事务性写入退款明细,使用 requestId 幂等;若支付网关异步返回,保留 PENDING/UNKNOWN 并对账,不能超时就重新生成新退款。
- 用题目矛盾样例做算术检查:例 1 请求 50,CREDIT 40 与 PAYPAL 60,按列出的优先级应分 40+10,而非只退 30。
手动走一遍
例 2:Payment1 CREDIT 40,已有退款 20,故只剩 20;Payment2 PAYPAL 60 日期较早,Payment3 PAYPAL 40 日期较新。再退 50 时先 Payment1 退 20,再按同方式较新优先给 Payment3 退 30。题目初列 40+10 的输出忽略了已有退款。
规模与取舍
P 笔支付、R 条已有退款,聚合 O(P+R),排序 O(P log P),分配 O(P),额外空间 O(P);若交易不断新增,可按方式/时间维护索引。
易错点与追问
容易失分的边界
- 忽略之前已退金额,导致 payment 超额退款。
- 先按时间而非支付方式排序。
- 分配给下一笔前没有尽可能用满当前笔。
- 把冲突样例的一行输出当精确题意。
- 用浮点金额。
继续深挖
- 若部分退款在网关处理中,remaining 如何锁定?
- 退款请求重复提交怎样幂等?
- 同方式同时间如何稳定排序?
- 超额请求是否允许部分成功?
