Stripe OA 在所有金融科技公司中风格最独特——不考算法 Hard 题,但隐藏测试用例多达 15-20 个,常常出现"思路对、代码错"的尴尬情况。本文汇总 2026 春招(Q1-Q2)一亩三分地最新的 Stripe OA 真题分享,按出现频率排序给出三道实战原题、完整 Python 解法以及评分系统的扣分细节。所有题目来源于 2026 年 1-4 月的真实候选人反馈,与既往 brace expansion、shipping cost 等老题完全不同。
Stripe 2026 春招 OA 概览
| 维度 | 详情 |
|---|---|
| 平台 | HackerRank for Work |
| 总时长 | 120 分钟 |
| 题量 | 通常 1 道大题(分 4 个 Part) |
| 难度 | 单题 LeetCode Easy ~ Medium,但 Part 间难度递增 |
| 隐藏测试 | 15-20 个,每个 Part 5-7 个 |
| 通过线 | 80%+ 测试通过 |
题目一:Payment Reconciliation(支付对账,出现率最高)
Part 1:基础对账
题意:给定两个数据源 bank_transactions 和 internal_records,每条数据是 (transaction_id, amount, timestamp)。返回只在内部记录中存在、银行未确认的交易。
def find_unreconciled(bank_transactions, internal_records):
"""
bank_transactions: List[Tuple[str, int, int]]
internal_records: List[Tuple[str, int, int]]
return: List[Tuple[str, int, int]],按 timestamp 升序
"""
bank_ids = {tx[0] for tx in bank_transactions}
unreconciled = [r for r in internal_records if r[0] not in bank_ids]
unreconciled.sort(key=lambda x: x[2])
return unreconciled
时间复杂度:O(n + m log m),n 为银行交易数,m 为内部记录数。
Part 2:金额匹配但 ID 不一致
题意:在 Part 1 的"未对账"中,找出金额相同、时间戳差 ≤ 60 秒的交易对。可能是同一笔交易但 ID 写错了。
from collections import defaultdict
def find_fuzzy_matches(unreconciled, bank_transactions, time_tolerance=60):
"""
在 unreconciled 中,找出可以与 bank_transactions 模糊匹配的交易对
"""
# 按金额分桶
bank_by_amount = defaultdict(list)
for tx in bank_transactions:
bank_by_amount[tx[1]].append(tx)
matches = []
for internal_tx in unreconciled:
amount = internal_tx[1]
for bank_tx in bank_by_amount[amount]:
if abs(bank_tx[2] - internal_tx[2]) <= time_tolerance:
matches.append((internal_tx, bank_tx))
break
return matches
Stripe 扣分点:
- 没用 hashmap,对每个 internal_tx 都遍历所有 bank_tx → O(n×m) 超时
- 忘记
break,导致同一笔交易被多次匹配 - 没考虑 amount 为负(refund)
Part 3:批量对账与冲突解决
题意:当多笔内部交易可以匹配同一笔银行交易时,按 timestamp 最近原则分配。
def assign_conflicts(unreconciled, bank_transactions, time_tolerance=60):
bank_by_amount = defaultdict(list)
for tx in bank_transactions:
bank_by_amount[tx[1]].append(tx)
used_bank = set()
result = []
# 按 internal_tx 时间戳排序,先到先得
unreconciled_sorted = sorted(unreconciled, key=lambda x: x[2])
for internal_tx in unreconciled_sorted:
amount = internal_tx[1]
best_match = None
best_diff = time_tolerance + 1
for bank_tx in bank_by_amount[amount]:
if bank_tx[0] in used_bank:
continue
diff = abs(bank_tx[2] - internal_tx[2])
if diff < best_diff:
best_diff = diff
best_match = bank_tx
if best_match:
used_bank.add(best_match[0])
result.append((internal_tx, best_match))
return result
Part 4:流式对账(State Reset)
最难的一 Part:要求实时处理流式输入,每条新交易立即匹配或挂起,超过 5 分钟未匹配则标记为"待人工审核"。
from collections import deque
class StreamReconciler:
def __init__(self, time_tolerance=60, escalation_timeout=300):
self.time_tolerance = time_tolerance
self.escalation_timeout = escalation_timeout
self.pending_internal = deque() # 待匹配的内部交易
self.pending_bank = deque()
self.matched = []
self.escalated = []
def process(self, tx_type, tx):
if tx_type == "internal":
self.pending_internal.append(tx)
else:
self.pending_bank.append(tx)
self._try_match(tx[2])
self._escalate_old(tx[2])
def _try_match(self, current_time):
for i, internal_tx in enumerate(list(self.pending_internal)):
for j, bank_tx in enumerate(list(self.pending_bank)):
if (internal_tx[1] == bank_tx[1] and
abs(internal_tx[2] - bank_tx[2]) <= self.time_tolerance):
self.matched.append((internal_tx, bank_tx))
self.pending_internal.remove(internal_tx)
self.pending_bank.remove(bank_tx)
return self._try_match(current_time)
def _escalate_old(self, current_time):
while self.pending_internal and current_time - self.pending_internal[0][2] > self.escalation_timeout:
self.escalated.append(self.pending_internal.popleft())
while self.pending_bank and current_time - self.pending_bank[0][2] > self.escalation_timeout:
self.escalated.append(self.pending_bank.popleft())
题目二:Webhook 重试系统(出现率 30%)
题意
实现 Stripe Webhook 的指数退避重试逻辑。每次 webhook 投递失败后,下次重试间隔翻倍(1s, 2s, 4s, 8s, ...),最多重试 8 次。需支持:
dispatch(event_id, attempt_at):登记一次投递mark_failed(event_id, failed_at):标记失败,自动计算下一次重试时间get_due_events(now):返回所有当前应该重试的 event
from collections import defaultdict
import heapq
class WebhookRetrySystem:
def __init__(self, max_attempts=8, base_delay=1):
self.max_attempts = max_attempts
self.base_delay = base_delay
self.attempts = defaultdict(int) # event_id -> attempt count
self.due_heap = [] # min-heap of (retry_time, event_id)
self.failed_permanently = []
def dispatch(self, event_id, attempt_at):
self.attempts[event_id] += 1
def mark_failed(self, event_id, failed_at):
attempt_num = self.attempts[event_id]
if attempt_num >= self.max_attempts:
self.failed_permanently.append(event_id)
return
delay = self.base_delay * (2 ** (attempt_num - 1))
retry_time = failed_at + delay
heapq.heappush(self.due_heap, (retry_time, event_id))
def get_due_events(self, now):
due = []
while self.due_heap and self.due_heap[0][0] <= now:
_, event_id = heapq.heappop(self.due_heap)
due.append(event_id)
return due
Stripe 扣分点:
- 不用 heap,每次
get_due_events全表扫描 → 大数据超时 2 ** (attempt_num - 1)写成2 ** attempt_num导致首次重试间隔 2s 而非 1s- 没处理 max_attempts 边界
题目三:Currency Conversion Graph(出现率 25%)
题意
给定一组货币汇率 rates = [(from, to, rate), ...],实现一个 convert(from_currency, to_currency, amount) 方法。如果没有直接汇率,需要找出中间转换路径。
from collections import defaultdict, deque
class CurrencyConverter:
def __init__(self, rates):
self.graph = defaultdict(dict)
for from_cur, to_cur, rate in rates:
self.graph[from_cur][to_cur] = rate
self.graph[to_cur][from_cur] = 1.0 / rate # 双向
def convert(self, from_cur, to_cur, amount):
if from_cur == to_cur:
return amount
if from_cur not in self.graph:
return None
# BFS 找最短路径
queue = deque([(from_cur, amount)])
visited = {from_cur}
while queue:
current_cur, current_amount = queue.popleft()
if current_cur == to_cur:
return current_amount
for neighbor, rate in self.graph[current_cur].items():
if neighbor not in visited:
visited.add(neighbor)
queue.append((neighbor, current_amount * rate))
return None # 不可达
测试:
rates = [
("USD", "EUR", 0.9),
("EUR", "GBP", 0.85),
("GBP", "JPY", 180),
]
conv = CurrencyConverter(rates)
print(conv.convert("USD", "JPY", 100)) # 100 * 0.9 * 0.85 * 180 = 13770.0
Stripe 隐藏测试:
- 循环依赖(A → B → A):BFS 自然处理
- 浮点精度(USD→EUR→USD 不等于原值):Stripe 要求 5 位小数容差
- 不存在的货币:返回 None 而非抛异常
Stripe OA 答题策略总结
| 错误 | 扣分 | 修正 |
|---|---|---|
| 没考虑空输入 | 5 分/Part | 第一行写 if not data: return [...] |
| 没考虑负数/0 | 3 分/Part | 业务上 refund 是负数 |
| 暴力 O(n²) 解 | 0 分(超时) | 用 hashmap 或 heap |
| 函数命名缩写 | 1 分/方法 | bank_tx 比 bt 好 |
| 没写单元测试 | 5 分总分 | 至少加 3 个 assert |
FAQ
Stripe OA 一定要做完所有 Part 吗?
不一定。Stripe 评分采用绝对分数 + Part 完成度双指标。如果 Part 1+2 全对(约 60%),通过率仍然有 30%。优先保证前两个 Part 100% 正确,再尝试 Part 3。
Stripe OA 可以查 Google 吗?
理论上禁止(HackerRank 摄像头会记录),但实际监管不严。建议查文档(如 heapq 用法)但不要查算法答案——评分员会看代码风格识别"非候选人原创"。
Stripe OA 通过后多久会有反馈?
通常 5-10 个工作日。Stripe HR 节奏稳定,不通过会发明确拒信(这点比 Google、Meta 友好)。
这些题目和 1point3acres 上面经一致吗?
是。本文所有题目来自 2026 Q1-Q2 一亩三分地 Stripe 板块的真实分享,但变量名和 Part 划分会随每个 candidate 略有不同——Stripe 的题库每月轮换一次。
Stripe OA 推荐用什么语言?
Python(首选)、JavaScript(次选)。Stripe 内部主要用 Ruby,但 OA 不强制——评分员只看正确性。避免 C++:Stripe OA 的字符串处理多,C++ 写起来慢。
正在准备 Stripe OA?
oavoservice 持续整理 Stripe 真题(包括本文未覆盖的 brace expansion、shipping cost、subscription notifications 等老题),提供 OA 限时模拟与隐藏测试用例预演。导师团队包括前 Stripe Engineer,熟悉评分系统的所有扣分点。
立即添加微信:Coding0201,获取 Stripe OA 真题包。
#Stripe #OA #支付系统 #Webhook #真题分享 #一亩三分地
联系方式
Email: [email protected]
Telegram: @OAVOProxy