题目重点:多帖同题族给账户、存转款、支出排行、定时付款取消和合并后历史余额;用事件/快照保留旧账户时间线。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版所有 API 调用带递增 timestamp,金额为正整数,账户 ID 唯一;操作先结算到期且未取消的 scheduled payment,再处理当前命令。题目未公开同时间戳并列及失败付款规则。
- 定时付款有唯一 paymentId、source、target(若为 transfer)、amount、executeAt、status;到期余额不足时训练版标记 failed,不重试。
- merge(A,B,t) 将 B 的当前可用余额/支出与未执行付款迁到 A,B 从当前活跃表删除,但历史查询 B 在 t 前的余额仍可回答;这些字段合并口径需和具体 OA 规格核对。
解题路线
- Level1 用 account→balance 保存账户,create/deposit/transfer 统一验证存在、余额、金额,transfer 原子扣加;每次成功或失败操作的历史影响要明确。
- Level2 维护每账户累计外流支出(transfer 或实际执行付款,具体口径按题面),top-k 用 (-spent,accountId) 排序;避免把 deposit 计入支出。
- Level3 用按 (executeAt,paymentId) 排序的小顶堆存待付款,paymentId→记录表支持取消;每个带时间操作前反复弹 executeAt≤now 的付款,跳过已取消/已执行。调用返回的 paymentId 后续取消必须原样识别。
- Level4 merge 时将 B 的当前余额与 pending payment 关系迁到 A,并建立旧 ID→历史时间线/合并事件;历史查询先按 queryTime 查对应账户当时事件或快照,而非只读当前活跃 map。
- 通过时间边界、同日多付款、取消已执行、余额不足、A/B 合并后的付款、查询合并前 B 的余额做状态测试;若原题对合并后的旧账户查询另有语义,以原题接口为准。
手动走一遍
训练例:t=1 创建 A/B,各存 100/40;t=2 A 排 t=5 付款 30 给 B;t=4 合并 B 入 A 后,A 当前余额 140,待付款的 target 需改指 A 或按题意拒绝自转;t=5 运行前要先解释目标账户合并语义。若历史 query(B,t=3),应仍可读 40,不能因为 B 已删除而返回不存在。这个例子强调题面必须补齐 merge target 规则。
规模与取舍
普通账户操作平均 O(1),每笔到期付款入/出堆 O(log P),P 为 pending 数;top-k 直接排序 A 个账户 O(A log A),历史按账户事件二分 O(log H),存储 O(A+P+H)。合并若逐个迁 B 的付款,成本 O(P_B)。
易错点与追问
容易失分的边界
- 每个 API 都手写到期处理,漏一处导致时间推进不一致。
- 取消时返回/查找的 paymentId 不稳定。
- merge 直接删 B 的全部数据,历史余额无法查。
- 把排队付款当支出计数,而非实际执行时才计。
- 把不题目的 schedule transfer/payment 与合并细节伪装成统一官方原题。
继续深挖
- 同时间戳付款与 merge 谁先?
- 余额不足付款是失败、延迟还是重试?
- 合并后发给旧 B 的 scheduled transfer 如何路由?
- 历史查询如何用快照压缩事件日志?
