题目重点:多篇 OA 给出分层 Banking 操作;区分普通转账、定时支付/取消和离线转账变体,并用事件时间处理合并历史。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版时间戳单调不减、金额为正整数最小货币单位,账户创建初始余额 0;具体返回类型/时间相等执行顺序以真实题面为准。
- 普通转账/定时支付只有在源账户余额足够且目标有效时成功;只有成功转出金额计入 spend,失败不改变状态。
- 定时支付以 (dueTime,creationOrder) 排序,处理当前操作时先执行 dueTime≤timestamp 的待办;题目只说‘在该 timestamp 之前’,等号边界需确认。
- 合并账户后老 ID 不再接受新操作,但历史查询可以按别名/归档找到当时余额;题目描述没给多次合并/退款的精确接口。
解题路线
- Level 1 用 accountId→状态,create 唯一,deposit/transfer 在校验后原子地改双方余额;全部方法经 advance(timestamp) 统一入口。
- Level 2 为每账户维护 successfulOutgoingAmount,Top N 按金额降序与明确 ID tie-break 排;不要把存款、收款或失败支付算作花费。
- Level 3 把定时支付存在按 (dueTime,creationOrder) 的优先队列和 ID 状态表;advance(t) 逐一弹出到期且未取消项,执行时再次检查余额,再更新 spend。取消只改变仍待执行的任务。
- Level 4 用事件/快照记录每个账户余额随时间变化,合并时在当前时间迁移余额与交易归属,并保留源 ID 的历史事件;查询历史余额先定位当时有效 ID 与最近 ≤time 的快照/事件。
- 把 的离线转账/删除转账列为不同分支:先问离线是预约、待接受还是离线授权;明确取消对历史 spend/余额的逆操作,不能硬套定时支付逻辑。
手动走一遍
训练例:A 余额 100,安排 t=10 支付 30;在 t=12 调用 deposit 前,advance(12) 先扣 30,使 A 余额 70、spend=30,然后处理存入。若 t=8 取消,t=12 不扣。合并 A→B 后,查询 t=5 的 A 余额仍取历史记录,而非直接读 B 当前余额。具体数字为训练示例。
规模与取舍
基础操作哈希索引均摊 O(1);到期任务逐个堆操作 O(log P),每个任务生命周期最多入/出堆一次;Top N 基线 O(A log A),历史查询对单账户按时间索引 O(log H)。空间 O(A+P+H),A 为账户、P 为预约、H 为历史事件数。
易错点与追问
容易失分的边界
- 只在 schedule_payment 当下改余额,没有在后续操作前结算。
- 取消后任务还留在堆中却执行,未核状态表。
- Top Spenders 用账户余额或转账次数排序。
- 合并时删除旧 ID 历史,无法回答过去余额。
- 把离线转账变体擅自解释成定时支付。
继续深挖
- 同一时刻多笔到期支付按什么顺序?
- 支付失败是否重试,spend 如何变化?
- 合并后旧 ID 的历史查询如何解释?
- 时间戳乱序输入会改变什么?
