SWE · Onsite Coding 5

Pinterest Account Balance:任意可行清算方案怎么构造

题目明确不要求最少笔数;先算净余额,再让净流入者向净流出者回付,用守恒不变量验证任意方案。

题目重点:题目明确不要求最少笔数;先算净余额,再让净流入者向净流出者回付,用守恒不变量验证任意方案。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • amount 是非负整数最小货币单位;原始 from→to 表示 from 支付 to,payback 是反向现金流,二者合计后每人的净额为 0。
  • 同一个人可在多条交易中出现;允许任意可行 payback 列表,不求笔数最少;0 金额可忽略。
  • 若题目把原始交易解释成欠款而非已发生付款,输出方向应反过来;现场必须确认语义。

解题路线

  1. 扫描交易,from 减 amount、to 加 amount,得到每人的净流入。所有人的净额总和应为 0,是第一条校验不变量。
  2. 将净额为正的人放入 surplus 列表、负额放入 deficit 列表;当前正负双方配对,付款 amount=min(正余额,负余额绝对值)。
  3. 记录正余额者作为 payer、负余额者作为 receiver,双方余额同步减少;每笔至少清空一方,直到全为 0。
  4. 验证时将原始交易与 payback 当同方向现金流再次累计;每个人最终净额必须为 0,且每笔金额为正。

手动走一遍

原始 A→B 10、A→C 5、C→B 2 后,A=-15、B=+12、C=+3。可输出 B→A 12、C→A 3;把 payback 加入原交易后 A/B/C 都是 0。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

"""Return any valid payback list; do not minimize transfer count."""

from collections import defaultdict


def settle_accounts(transactions: list[tuple[str, str, int]]):
    balance = defaultdict(int)
    for sender, receiver, amount in transactions:
        if amount < 0:
            raise ValueError("amount must be nonnegative integer cents")
        balance[sender] -= amount
        balance[receiver] += amount
    deficits = [[person, -amount] for person, amount in balance.items() if amount < 0]
    surpluses = [[person, amount] for person, amount in balance.items() if amount > 0]
    result = []
    deficit_index = surplus_index = 0
    while deficit_index < len(deficits) and surplus_index < len(surpluses):
        receiver, deficit = deficits[deficit_index]
        payer, surplus = surpluses[surplus_index]
        amount = min(deficit, surplus)
        result.append((payer, receiver, amount))
        deficits[deficit_index][1] -= amount
        surpluses[surplus_index][1] -= amount
        if deficits[deficit_index][1] == 0:
            deficit_index += 1
        if surpluses[surplus_index][1] == 0:
            surplus_index += 1
    return result

复杂度

T 条交易、P 个不同账户:算净额 O(T)、配对 O(P),总 O(T+P) 时间、O(P) 额外空间;至多 P−1 笔清算(仅计非零余额账户)。不要求最少笔数是可以线性求解的关键。

易错点与追问

容易失分的边界

  • 误把本题当最少笔数版,做指数级回溯。
  • 没确认原始 from/to 是已付款还是欠款,造成 payback 方向反。
  • 使用浮点数表示金钱,累积后无法精确清零。
  • 允许零金额或对自身转账进入输出。

继续深挖

  • 若要尽量减少笔数,为什么简单双指针不保证最优?
  • 多币种交易如何处理汇率和结算时点?
  • 真实支付系统如何保证转账幂等和失败后的账务一致?
✓已复制微信号!