目录
正在加载目录...

Stripe OA|9.6,一道题把计费系统做了个遍

Stripe OA 就一道题。进去看到题目的第一感受是:这更像是在做一个真实的工程需求。一道大题,分四个 Part 逐步解锁,每个 Part 在上一个基础上加功能——固定月费、月中变更、用量计费、阶梯定价,把 Stripe 账单引擎的核心逻辑做了个遍。

这种题型的难点不是算法,是你能不能在不推翻之前代码的情况下把新功能扩展进去。每个 Part 通过测例之后,下一个 Part 的规则接着来,写得不够模块化就得大改,写得好就只是加一个函数。

大约 20 分钟写完,把做题过程记下来——包括踩过的坑。

Stripe OA|9.6,一道题把计费系统做了个遍

Part 1

Stripe OA|9.6,一道题把计费系统做了个遍

Part 1 就是固定月费订阅,所有订阅从第 1 天生效,月费完整计入,按用户汇总,最后 floor 取整输出。

我一开始大概两分钟就写完了:

user_totals = {}
for sub in subscriptions:
    uid = sub['user_id']
    user_totals[uid] = user_totals.get(uid, 0) + sub['monthly_cost']

result = [[uid, str(math.floor(total))] for uid, total in user_totals.items()]

测例全过。然后 Part 2 的规则出来了,我意识到这个结构撑不住后面的变更逻辑,得改。

Part 2

Stripe OA|9.6,一道题把计费系统做了个遍

Part 2 加入了月中变更——用户可以在月中升级或降级订阅,变更之后按剩余天数按比例计费。

第一个坑:变更列表不是有序的。

我第一次写的时候直接按照变更列表的顺序处理,前三个测例都过了,第四个挂掉了。检查了几分钟才发现——变更列表没有保证按时间顺序,必须先排序再处理。加了一行 sorted_changes = sorted(changes, key=lambda x: x['change_day']) 之后才对。

第二个坑:浮点精度。

按比例计费的公式是 monthly_cost × days_active / 30。我第一版用了浮点:

charge = sub['monthly_cost'] * days_active / 30  # 错的

这在金融系统里不可接受——浮点误差会让结果差一两分,测例就挂了。

正确做法是先做整数乘法,最后再除:

charge = sub['monthly_cost'] * days_active  # 先乘,保持整数
# 累加到用户总额之后,最后统一除以 30 再 floor

第三个坑:月末漏结算。

变更处理完之后,仍在生效的订阅还没有结算到第 30 天。我第一次提交忘了这一步,测例里有一个用户只有初始订阅没有变更,结果他的费用是 0——这才意识到月末结算必须单独处理。

修正之后的核心逻辑大概是这样:

# 按 change_day 排序(关键!)
for change in sorted(changes, key=lambda x: x['change_day']):
    sub_id = change['sub_id']
    change_day = change['change_day']
    s = sub_state[sub_id]

    # 结算到变更前一天(整数运算)
    days = change_day - s['start']
    user_charges[s['user_id']] += s['cost'] * days

    # 更新状态
    s['cost'] = change['new_cost']
    s['start'] = change_day

# 月末结算所有仍有效的订阅(不能漏!)
for sub_id, s in sub_state.items():
    days = 30 - s['start'] + 1
    user_charges[s['user_id']] += s['cost'] * days

# 最后统一除以 30 再 floor
final = {uid: math.floor(total / 30) for uid, total in user_charges.items()}

Part 2 通过之后,我意识到 sub_state 的结构设计是对的——后面加功能只需要在外面包一层,不用动这块逻辑。

Part 3 & Part 4

Part 3 加了用量计费,flat 单价,按 user_id + product_id 汇总用量再乘单价。

Part 4 把 flat 改成阶梯定价——每个产品有一组”上限 + 单价”的阶梯,用量从第一档开始消化,超出当前档的进入下一档。

我把 Part 3 的 flat 产品看成只有一档、上限为无穷大的特殊阶梯,这样 Part 3 和 Part 4 可以共用同一套代码:

def calc_tiered(qty, tiers):
    # tiers: [(up_to, unit_cost), ...], up_to=None 表示无限
    total, remaining = 0, qty
    for up_to, unit_cost in tiers:
        if remaining <= 0:
            break
        bucket = remaining if up_to is None else min(remaining, up_to)
        total += bucket * unit_cost
        remaining -= bucket
    return total

阶梯边界的坑:用量恰好等于某档上限时,要确保进入下一档从 0 开始,不要把边界用量重复计算。用 min(remaining, up_to) 的写法天然处理了这个问题,不需要额外判断。

用量费用和订阅费用最后合并到一起,对每个用户的总和做最终的 floor。注意:floor 只做一次,在最终汇总之后,不是对每条订阅或每笔用量分别 floor。这个时机搞错,多用户累计的误差会被放大。

做完这道题的感受

Stripe OA 的考察点和普通算法题完全不同。

它考的不是你会不会用堆或者二分,是你面对一个逐步增加需求的系统,能不能写出足够干净的代码让每个 Part 的扩展只需要加函数、不需要推翻结构。

三个最容易出错的判断——变更必须先排序、金额必须用整数运算、floor 只做一次——都不是算法问题,是工程判断。这才是 Stripe 真正想看的东西。

Stripe 面试完整流程

OA 只是第一步,Stripe 的完整流程偏工程向,每一环都在考真实的工程判断能力。

OA:Stripe 自有平台,一道工程大题分多个 Part,不是多道独立 LC 题。时间通常 60 到 90 分钟,但写得熟的话 20 到 30 分钟可以搞定。

Phone Screen(45 到 60 分钟):一道 coding 题加简历深挖。题目风格和 OA 类似,偏工程实现,面试官会追问代码可维护性和边界处理。

Onsite(4 到 5 轮):

Coding 轮(2 轮)——可能是扩展 OA 的题目,也可能是全新的业务场景题,风格一致偏工程。

System Design 轮(1 轮)——Payment Processing、Subscription Billing、Fraud Detection 是高频方向,和 OA 题的业务逻辑直接相关。

Inclusion 轮(1 轮)——Stripe 特有,考 culture fit 和价值观,不考技术。

Manager 轮(1 轮)——聊职业规划和 team fit。

整体 3 到 6 周,Stripe 节奏偏快。

FAQ

Stripe OA 是限时的吗,可以中途暂停吗?
一旦开始计时就不能暂停。建议进去之前把所有可能干扰的事情处理好,确保有完整的 60 到 90 分钟不被打断。

Part 1 写得很简单,要不要一开始就考虑后面 Part 的扩展性?
要。Part 1 的结构决定了后面能不能顺畅扩展——如果 Part 1 把所有逻辑都写在一个函数里,到 Part 2 加变更逻辑时基本要重写。建议 Part 1 就把”订阅状态维护”和”费用结算”分成两个独立的逻辑块,后面加功能只需要在外面包一层。

变更列表题目说会不会乱序?
题面不会明说,但测例里会有乱序的情况——这是专门考你会不会主动排序的 edge case,默认先排序是最安全的做法。

如果用量很大、阶梯档数很多,会不会超时?
不会,阶梯计费是 O(tier 数量),tier 数量在这类题里通常很小(3 到 5 档),整体复杂度是 O(变更数 log 变更数 + 用量数 + tier 数),不存在超时风险。

floor 只做一次还是每步都 floor?
只做一次,在最终汇总之后。对中间结果频繁 floor 会积累误差,题目测例会专门卡这个——某些用户的累计订阅费用在 floor 前后差一分,中间 floor 会让结果偏低。

没有 Stripe 产品背景可以做这道题吗?
完全可以,题面会给出所有规则,不需要提前了解 Stripe 的 API 或业务。但理解”为什么账单系统要用整数美分”这类工程常识会帮你更快判断正确做法,这是通用的金融系统工程直觉。

想提前把这些坑踩完?

有在准备 Stripe 或其他支付/金融科技公司的同学,可以来聊聊。InterviewShow 做过 Stripe、PayPal、Coinbase 这些公司的面试,计费系统的工程实现、支付系统设计、多 Part 题的结构设计思路都有专门覆盖,有需要的来聊。

END