Coinbase OA 面经 2026:账户系统、Top K、定时转账与历史余额全解
Coinbase OA 面经 2026 是本文焦点。首先,这是一份 2026 年最新复盘。并且,这是我们学员贡献的最新面经。因此,内容紧贴真实考场节奏。
此外,这套题覆盖四层能力。你会先做账户与转账。然后会做 Top K 排行。与此同时,还要处理定时任务与账户合并。总而言之,这题考的是状态建模能力。
Coinbase OA 面经 2026:2026 面试流程深度复盘
首先,Coinbase OA 面经 2026 常见三段流程。第一段是限时编码。第二段是代码讲解。第三段是行为问答。与此同时,面试官会持续追问边界条件。
其次,开场通常先给基础账户题。你要快速完成 Create Account。你还要写 Transfer funds。因此,数据结构要先选哈希表。异常分支也要一次写全。
此外,中段会加 Top K 追问。面试官会看复杂度意识。换句话说,你要知道排序和堆的取舍。k 很小时,最小堆更稳。
但是,后段会加入定时转账。你要按时间触发执行。你还要保证同时间任务顺序稳定。因此,优先队列要带时间和序号。
最后,Level 4 会考账户合并。旧账户会被逻辑删除。与此同时,还要支持旧时间点查询。总而言之,这就是 Coinbase OA 面经 2026 的分水岭。
核心题目解析
1) 账户系统基础操作
首先,Create Account 要保证唯一。重复创建必须失败。其次,Transfer funds 要校验双方存在。余额不足也要立刻失败。
此外,转账更新必须原子化。借方与贷方要同成同败。否则会出现对账差异。具体来说,可把更新封装成单事务函数。
2) 消费排行查询 Top K
首先,累计消费建议单独维护。只有成功转出才累加。其次,查询前 k 时要定义同分规则。常见做法是账号字典序升序。
此外,数据量小时可直接全排序。数据量大时可用最小堆。这样复杂度可到 O(n log k)。因此,扩展追问更容易拿分。
3) 定时转账 schedule transfer
首先,调度结构用最小堆。键为执行时间与自增序号。这样同秒任务也有确定顺序。与此同时,任务状态要有 pending/executed/failed。
其次,每次新请求到来前。先执行 run_due(now)。然后再处理当前请求。换句话说,系统时钟不能倒退。
4) 账户合并与历史余额查询
首先,Merge account 不只是余额相加。你还要处理身份映射。旧账户会退出当前态。与此同时,旧账户历史要完整保留。
其次,Get balance(account, ts) 不能读当前余额。你要在历史时间线做二分。这样查询复杂度是 O(log n)。因此,历史快照结构很关键。
5) Level 4 关键难点与易错点
但是,最容易错的是旧账户查询。旧账户已被合并删除。面试官仍会问合并前余额。你若只存当前态会直接失分。
因此,要做“当前态”和“历史态”分离。当前态只服务实时操作。历史态按时间写快照。总而言之,这一点就是 Coinbase OA 面经 2026 的核心难点。
系统设计流程图(Mermaid)
flowchart TD
A[请求进入] --> B{请求类型}
B -->|Create Account| C[写入当前余额]
B -->|Transfer funds| D[校验并原子更新]
B -->|Top K| E[读取累计消费]
B -->|schedule transfer| F[写入最小堆]
B -->|Merge account| G[迁移余额并记录 merge_ts]
B -->|Get balance(ts)| H[读取历史快照]
F --> I[run_due(now) 执行到期任务]
I --> D
D --> J[更新消费统计]
G --> K[逻辑删除旧账户当前态]
K --> H
Python 参考代码(面试可直接讲)
from collections import defaultdict
import heapq
from typing import Dict, List, Optional, Tuple
class BankSystem:
def __init__(self) -> None:
# 当前态:只保存可操作账户
self.bal: Dict[str, int] = {}
# 消费统计:仅统计成功转出金额
self.spent: Dict[str, int] = defaultdict(int)
# 历史态:account -> [(ts, balance_or_none)]
# none 表示该时间点后账户已失效
self.history: Dict[str, List[Tuple[int, Optional[int]]]] = defaultdict(list)
# 调度堆:(execute_ts, seq, from_id, to_id, amount, task_id)
self.pq: List[Tuple[int, int, str, str, int, str]] = []
self.seq = 0
self.task_status: Dict[str, str] = {}
# 账户合并映射:old_id -> (merge_ts, new_id)
self.merge_to: Dict[str, Tuple[int, str]] = {}
def _append_history(self, account: str, ts: int, value: Optional[int]) -> None:
self.history[account].append((ts, value))
def _snapshot_at(self, account: str, ts: int) -> Optional[int]:
arr = self.history.get(account, [])
if not arr:
return None
# 按时间二分,找最后一个 <= ts 的快照
lo, hi = 0, len(arr)
while lo < hi:
mid = (lo + hi) // 2
if arr[mid][0] <= ts:
lo = mid + 1
else:
hi = mid
idx = lo - 1
if idx < 0:
return None
return arr[idx][1]
def run_due(self, now: int) -> None:
while self.pq and self.pq[0][0] <= now:
_, _, src, dst, amount, task_id = heapq.heappop(self.pq)
# 到期时再校验账户与余额
if src not in self.bal or dst not in self.bal:
self.task_status[task_id] = "failed"
continue
if self.bal[src] < amount:
self.task_status[task_id] = "failed"
continue
self.bal[src] -= amount
self.bal[dst] += amount
self.spent[src] += amount
self._append_history(src, now, self.bal[src])
self._append_history(dst, now, self.bal[dst])
self.task_status[task_id] = "executed"
def create_account(self, account: str, ts: int, initial: int = 0) -> bool:
if initial < 0:
return False
if account in self.bal or account in self.merge_to:
return False
self.bal[account] = initial
self._append_history(account, ts, initial)
return True
def transfer(self, src: str, dst: str, amount: int, ts: int) -> bool:
self.run_due(ts)
if amount <= 0 or src == dst:
return False
if src not in self.bal or dst not in self.bal:
return False
if self.bal[src] < amount:
return False
self.bal[src] -= amount
self.bal[dst] += amount
self.spent[src] += amount
self._append_history(src, ts, self.bal[src])
self._append_history(dst, ts, self.bal[dst])
return True
def top_k_spenders(self, k: int, now: Optional[int] = None) -> List[Tuple[str, int]]:
if now is not None:
self.run_due(now)
if k <= 0:
return []
# 返回当前有效账户的消费排行
rows = [(acc, self.spent.get(acc, 0)) for acc in self.bal.keys()]
rows.sort(key=lambda x: (-x[1], x[0]))
return rows[:k]
def schedule_transfer(
self, src: str, dst: str, amount: int, execute_ts: int, now: int
) -> Optional[str]:
self.run_due(now)
if amount <= 0 or src == dst:
return None
task_id = f"tx-{self.seq}"
heapq.heappush(self.pq, (execute_ts, self.seq, src, dst, amount, task_id))
self.task_status[task_id] = "pending"
self.seq += 1
return task_id
def merge_account(self, keep: str, old: str, ts: int) -> bool:
self.run_due(ts)
if keep == old:
return False
if keep not in self.bal or old not in self.bal:
return False
moved = self.bal[old]
self.bal[keep] += moved
self._append_history(keep, ts, self.bal[keep])
# 逻辑删除 old 的当前态,但保留历史态
self._append_history(old, ts, None)
self.merge_to[old] = (ts, keep)
del self.bal[old]
return True
def get_balance(self, account: str, ts: int) -> Optional[int]:
# 关键规则:旧账户在 merge_ts 之后视为不存在
if account in self.merge_to:
merge_ts, _ = self.merge_to[account]
if ts >= merge_ts:
return None
return self._snapshot_at(account, ts)
高频边界用例清单
首先,重复创建同一账号应失败。
其次,src == dst 的转账应失败。
此外,余额不足时必须不改任何余额。
与此同时,k <= 0 应返回空列表。
但是,k 大于账户数时要全返回。
具体来说,同分账号要固定排序规则。
随后,同时间定时任务要按序号执行。
并且,任务到期时才校验余额。
最后,合并后旧账号查未来时间应空。
总而言之,旧账号查合并前时间应成功。
Coinbase OA 面经 2026:专家备考策略与高频考点
首先,Coinbase OA 面经 2026 的备考顺序要对。先练基础转账。再练 Top K。然后补调度和历史查询。这样提分最快。
其次,核心考点可按四条背。
因此,第一条是一致性与原子更新。
此外,第二条是复杂度与 Top K 取舍。
与此同时,第三条是时间驱动调度。
最后,第四条是历史态与当前态分离。
但是,行为题同样会拉开差距。你可以用 STAR 快速组织回答。每段都给数据结果。这样更像真实工程复盘。
STAR 模板可直接套用。
首先,S 讲业务背景和故障影响。
其次,T 讲你负责的明确目标。
然后,A 讲技术动作与取舍依据。
最后,R 讲结果指标与复盘改进。
此外,Coinbase OA 面经 2026 常见 BQ 有三类。
第一类是线上事故处理。
第二类是跨团队协作冲突。
第三类是性能与稳定性平衡。
总结与行动号召(CTA)
总而言之,Coinbase OA 面经 2026 的重点很清晰。你要先拿下一致性。你还要吃透历史查询。最后再打磨表达与讲解。
如果你想系统冲刺,请使用内部资源。
联系我们的专家进行一对一面试辅导
此外,你可补齐算法底层概念。
权威算法参考