← 返回博客列表 Persona OA 2026 真题解析:CodeSignal 内存数据库 Level 1-4 完整通关|一亩三分地
Persona

Persona OA 2026 真题解析:CodeSignal 内存数据库 Level 1-4 完整通关|一亩三分地

2026-05-15

Persona Identities 作为身份验证赛道的明星 Y Combinator 公司,2026 年放出大量 Backend / Full-stack 岗位。它的 OA 不走 LeetCode 路线,而是走 CodeSignal 的"四级渐进题"——一个题面随 Level 加码,前一关的代码必须能兼容后一关。最常见的就是这道**"In-Memory Database"**,几乎已经成为 Persona OA 的"标志题",类似 Ramp、Square 也都采用过类似框架。

本篇基于一亩三分地最近的 Persona OA 复盘,把 Level 1-4 完整拆开,给出可以一路递增重构的 Python 实现,并讲一遍每个 Level 容易"挂掉"的坑。

Persona OA 概览

维度 详情
平台 CodeSignal General Coding Framework
时长 90 分钟(含 IDE 熟悉时间)
题量 1 道大题 × 4 个 Level
测试用例 累计约 25-30 个
语言 Python / Java / Go / JS 均可,但 Python 通过率最高
满分 100 分(Level 1=20,Level 2=25,Level 3=25,Level 4=30)

CodeSignal 的特殊之处:每个 Level 只暴露当级测试,下一级要等通过当前级才能解锁。这意味着 Level 1 的实现如果耦合写死、不抽接口,到 Level 3 会被逼着大规模重写。

Level 1:基础 Key-Value 操作

题目描述

实现内存数据库支持以下命令:

返回值必须是字符串。

解题思路

天然两层 dict:db[key][field] = value。重点是处理"key 不存在"的情况,不要预先创建空 dict——否则 Level 4 会污染备份。

Python 解法

class InMemoryDB:
    def __init__(self):
        self.db = {}

    def set(self, key, field, value):
        self.db.setdefault(key, {})[field] = value
        return ""

    def get(self, key, field):
        return self.db.get(key, {}).get(field, "")

    def delete(self, key, field):
        if key in self.db and field in self.db[key]:
            del self.db[key][field]
            if not self.db[key]:
                del self.db[key]
            return "true"
        return "false"

时间复杂度:所有操作均摊 O(1) 空间复杂度:O(K·F),K=key 数,F=平均 field 数

Level 2:扫描与前缀查询

题目描述

新增两条命令:

解题思路

直接 sorted(self.db[key].items()) 排序就够。不要存有序结构(如 SortedDict)——Persona 的 Level 4 会做批量回滚,越简单越好维护。

Python 解法

    def scan(self, key):
        if key not in self.db:
            return ""
        items = sorted(self.db[key].items())
        return ", ".join(f"{f}({v})" for f, v in items)

    def scan_by_prefix(self, key, prefix):
        if key not in self.db:
            return ""
        items = sorted(
            (f, v) for f, v in self.db[key].items() if f.startswith(prefix)
        )
        return ", ".join(f"{f}({v})" for f, v in items)

时间复杂度:O(F log F),F = 该 key 下 field 数 空间复杂度:O(F)

Level 3:TTL 过期机制

题目描述

引入"时间戳"语义——每次命令都带一个时间戳参数:

过期判定严格 ts ≥ expire,等于也算过期。

解题思路

把 value 从 string 改为 (value, expire_at) 元组,expire_at = None 表示永久。所有读取路径都过同一个 helper_alive(key, field, ts),避免在 6 个方法里散落判断。

Python 解法

class InMemoryDB:
    def __init__(self):
        self.db = {}  # key -> field -> (value, expire_at|None)

    def _alive(self, key, field, ts):
        rec = self.db.get(key, {}).get(field)
        if rec is None:
            return None
        value, expire_at = rec
        if expire_at is not None and ts >= expire_at:
            return None
        return value

    def set_at(self, key, field, value, ts):
        self.db.setdefault(key, {})[field] = (value, None)
        return ""

    def set_at_with_ttl(self, key, field, value, ts, ttl):
        self.db.setdefault(key, {})[field] = (value, ts + ttl)
        return ""

    def get_at(self, key, field, ts):
        v = self._alive(key, field, ts)
        return "" if v is None else v

    def delete_at(self, key, field, ts):
        if self._alive(key, field, ts) is None:
            return "false"
        del self.db[key][field]
        return "true"

    def scan_at(self, key, ts):
        if key not in self.db:
            return ""
        live = sorted(
            (f, v) for f, (v, exp) in self.db[key].items()
            if exp is None or ts < exp
        )
        return ", ".join(f"{f}({v})" for f, v in live)

时间复杂度:读写均摊 O(1),扫描 O(F log F) 陷阱:很多人把过期项立即从 dict 中删除——这会让 Level 4 的"指定时间点恢复"丢数据。惰性过期才是正确做法。

Level 4:备份与恢复(Backup / Restore)

题目描述

新增:

解题思路

两个关键点:

  1. 快照存什么:不能存浅拷贝。要存 (field, value, remaining_ttl),其中 remaining_ttl = expire_at - backup_ts,永久项存 None
  2. 恢复时怎么重写 expire_atnew_expire = ts + remaining_ttl

很多人栽在第 2 步——直接把旧 expire_at 拷回来,结果恢复后所有 TTL 都"瞬间过期"。

Python 解法

import copy

class InMemoryDB:
    def __init__(self):
        self.db = {}
        self.backups = {}  # backup_ts -> snapshot

    # ... 省略 Level 1-3 方法,沿用上面 ...

    def backup(self, ts):
        snapshot = {}
        for key, fields in self.db.items():
            live = {}
            for f, (v, exp) in fields.items():
                if exp is None:
                    live[f] = (v, None)
                elif ts < exp:
                    live[f] = (v, exp - ts)  # 存"剩余时长"
            if live:
                snapshot[key] = live
        self.backups[ts] = snapshot
        return str(len(snapshot))

    def restore(self, ts, backup_ts):
        if backup_ts not in self.backups:
            return ""
        snap = self.backups[backup_ts]
        new_db = {}
        for key, fields in snap.items():
            new_fields = {}
            for f, (v, remaining) in fields.items():
                exp = None if remaining is None else ts + remaining
                new_fields[f] = (v, exp)
            new_db[key] = new_fields
        self.db = new_db
        return ""

时间复杂度:BACKUP O(K·F),RESTORE O(K·F) 空间复杂度:O(B·K·F),B = 备份次数

Level 4 易错点清单

  1. ❌ 直接 copy.deepcopy(self.db) 当快照——会把已过期数据带回来
  2. ❌ 恢复时不重置 expire_at——TTL 全部失效
  3. ❌ 把 SET_AT 写到 backup 里——backup 是"只读快照",不允许逆向影响 db
  4. ✅ 把"过滤过期 + 计算剩余 TTL"合并到一次遍历,节省一倍内存

Persona 备考策略

阶段 推荐练习
熟悉 CodeSignal LC 146 LRU Cache、LC 460 LFU Cache
状态机 LC 432 All O`one Data Structure、LC 1206 Skiplist
TTL 思维 Redis EXPIRE 文档 + LC 362 Hit Counter
备份恢复 git-style 增量快照思路、LC 1166 File System

面试节奏建议:Level 1 控制在 15 分钟内拿满,Level 2-3 各 20-25 分钟,Level 4 留 25-30 分钟。千万别 Level 1 就开始写"未来扩展性极佳的抽象类"——CodeSignal 不会因为代码"优雅"加分,只看测试通过率。


FAQ

Q1:Persona OA 难度怎么样?比 LeetCode Medium 难吗?

不能直接对比。单题难度不超过 LC Medium,但 Persona OA 考的是渐进式重构能力——4 个 Level 累计 90 分钟内不仅要写对,还要让前一级代码"无缝兼容"下一级。如果 Level 1 把 value 写死成字符串,Level 3 会非常痛苦。

Q2:Persona OA 用什么平台?时长多长?

CodeSignal General Coding Framework,90 分钟。注意:考前还会有一个 60 分钟的 General Coding Assessment(GCA)作为筛选,那个才是纯 LeetCode 题型。In-Memory Database 是 GCA 之后的 Practical Task。

Q3:Persona 后端岗和 Full-stack 岗的 OA 一样吗?

题目本身完全一样。只是 Full-stack 岗在 OA 通过后会加一轮 React/TypeScript 实战,后端则进入系统设计。OA 阶段不需要区分准备。

Q4:用什么语言通过率最高?

Python > Go > Java > JS。CodeSignal 的 Python 模板自带类型提示和 IDE 自动补全,写四级嵌套字典最快。Java 慎用——Map 嵌套泛型语法噪声会大量挤占 90 分钟时间。

Q5:Level 4 的 backup_ts 不存在怎么办?

题目原文里 RESTORE 给定 backup_ts 一定是之前 BACKUP 过的——但多个 backup 后再 RESTORE 较早的那一个是常见隐藏 case。建议用 dict 而不是 list 存 backups,按 ts 索引。

Q6:OA 通过后多久收到下一轮通知?

一亩三分地多数反馈是 3-7 个工作日。如果 7 天没消息建议主动跟进 recruiter——Persona 流程节奏快,hiring manager 经常直接发 calendar 邀请,邮件容易漏看。


正在准备 Persona / Ramp / Square 的 CodeSignal 系列 OA?

CodeSignal 的"四级题"考的不是算法天花板,而是工程化思维和状态管理。如果你想拿到我们整理的同类公司四级题题库(Persona、Ramp、Stripe、Square、Brex),或希望针对 Level 3-4 的状态机做 1v1 复盘,欢迎联系。

立即添加微信 Coding0201获取 CodeSignal 四级题完整题库

联系方式

Email: [email protected] Telegram: @OAVOProxy