← 返回博客列表 ZipRecruiter 2026 NG OA 真题:内存数据库 4 个 Level 全解析|TTL + Backup/Restore
ZipRecruiter

ZipRecruiter 2026 NG OA 真题:内存数据库 4 个 Level 全解析|TTL + Backup/Restore

2026-05-14

ZipRecruiter 2026 New Grad OA 不卷算法,但极度卷设计——一道大题分 4 个递进 Level:CRUD、Scan & Prefix、TTL 过期清理、Backup / Restore 快照。每个 Level 单独看都不难,但4 个 Level 必须共享一套数据结构——前面设计的偷懒会在后面付出代价。本文给出每个 Level 的最优数据结构、Python 完整解法与 ZipRecruiter codesignal 评分系统的隐藏 case 防御。

ZipRecruiter NG OA 概览

维度 详情
平台 CodeSignal Test
时长 90 分钟
题量 1 道大题,4 个 Level
难度 LeetCode Easy~Medium,重设计
通过线 80% 测试通过
评分维度 正确性 + Level 完成度

题目核心:In-memory Database

实现一个内存键值数据库,支持嵌套结构:

db[key][field] = value

key 是顶层名称,field 是 key 下的字段名。所有操作要么对 key 整体作用,要么对 (key, field) 作用。

Level 1:基础 CRUD

操作

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

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

    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

Level 1 关键

Level 2:Scan & Prefix Filtering

操作

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

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

Level 2 隐藏 case

Level 3:TTL(Time-to-Live)

操作

核心设计:每个字段存 (value, start, ttl) 三元组,ttl=None 表示永久。

def __init__(self):
    self.db: dict = {}

def _is_alive(self, entry, timestamp):
    value, start, ttl = entry
    if ttl is None:
        return True
    return timestamp < start + ttl

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

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

def get_at(self, key, field, timestamp):
    if key not in self.db or field not in self.db[key]:
        return None
    entry = self.db[key][field]
    if not self._is_alive(entry, timestamp):
        return None
    return entry[0]

def delete_at(self, key, field, timestamp):
    if key not in self.db or field not in self.db[key]:
        return False
    entry = self.db[key][field]
    if not self._is_alive(entry, timestamp):
        return False
    del self.db[key][field]
    if not self.db[key]:
        del self.db[key]
    return True

def scan_at(self, key, timestamp):
    if key not in self.db:
        return []
    alive = [
        (f, e[0]) for f, e in self.db[key].items()
        if self._is_alive(e, timestamp)
    ]
    return [f"{f}({v})" for f, v in sorted(alive)]

Level 3 三个高频扣分点

  1. scan 不能清理过期字段 —— 只过滤不删除,否则会破坏后续 set_at_with_ttl 的语义
  2. delete_at 对过期字段返回 False —— 已过期等价于"不存在"
  3. TTL 是 start + ttl 严格小于的判断 —— timestamp < start + ttl 而不是 <=

Level 4:Backup / Restore

操作

def __init__(self):
    self.db: dict = {}
    self.backups: list = []  # [(backup_ts, snapshot)]

def _snapshot(self, timestamp):
    snap = {}
    for key, fields in self.db.items():
        snap_fields = {}
        for f, (v, start, ttl) in fields.items():
            if ttl is None:
                snap_fields[f] = (v, None, None)
                continue
            remaining = start + ttl - timestamp
            if remaining > 0:
                snap_fields[f] = (v, timestamp, remaining)
        if snap_fields:
            snap[key] = snap_fields
    return snap

def backup(self, timestamp):
    self.backups.append((timestamp, self._snapshot(timestamp)))
    return str(sum(len(fs) for fs in self.backups[-1][1].values()))

def restore(self, timestamp, target_timestamp):
    candidate = None
    for bk_ts, snap in self.backups:
        if bk_ts <= target_timestamp:
            candidate = (bk_ts, snap)
    if candidate is None:
        self.db = {}
        return ""
    bk_ts, snap = candidate
    # Re-base TTL to the current timestamp
    self.db = {}
    for key, fields in snap.items():
        for f, (v, start, ttl) in fields.items():
            if ttl is None:
                self.db.setdefault(key, {})[f] = (v, timestamp, None)
            else:
                self.db.setdefault(key, {})[f] = (v, timestamp, ttl)
    return ""

Level 4 关键设计

ZipRecruiter OA 通关策略

1)Level 优先级:1 → 2 → 3 → 4

每个 Level 占总分约 25%。Level 1+2 写到 100% = 50% 保底,足以进入 CodeSignal 的 Top 30% 分位。Level 3 是难度突变点——TTL 设计错就 Level 3 全挂。Level 4 是 stretch goal。

2)数据结构一次到位

不要 Level 1 用 db[key][field] = value,Level 3 改成 (value, start, ttl)——会逼你重写 Level 1+2 的所有代码。Level 1 就用 tuple,永久字段用 (value, 0, None)

3)函数返回值类型一致

CodeSignal 评分对字符串 / None / boolean / "" 返回值类型敏感。题面要求返回什么就严格返回什么——get_at 返回 Noneset_at 返回 ""delete_at 返回 boolean。

FAQ

ZipRecruiter OA 通过率高吗?

整体约 40-50%。Level 1+2 完成度高的候选人通过率 70%+,Level 3 是淘汰主战场——TTL 语义稍有偏差会扣 25% 分。

CodeSignal Test 有调试环境吗?

有。CodeSignal 提供 stdout 打印 + 自定义测试 case 运行。强烈建议每完成一个 Level 手动跑 3-5 个边界 case:空 key、空 prefix、TTL 刚好过期、backup 后再 delete。

4 个 Level 都做完需要多久?

熟练 candidate 约 60-75 分钟。前 10 分钟规划 → 20 分钟 Level 1+2 → 30 分钟 Level 3 → 15 分钟 Level 4。Level 4 来不及的话保住 Level 3 满分也能进 final round。

这道题的"亲戚"是什么?

CodeSignal 同款数据库题:Snowflake、Optiver、Capital One、Roku 都有变体。前缀 + TTL 几乎是 CodeSignal 平台的标准模板,题面只换"数据库 → 仓库 → 用户系统"。

ZipRecruiter OA 之后会有什么轮次?

OA 通过后进入 1 轮 HR Phone Screen,再到 2-3 轮 Technical Onsite(含 1 轮 Behavioral + 1-2 轮 Coding + 1 轮 System Design for senior 岗位)。从 OA 到 onsite 平均 2-4 周。


正在准备 ZipRecruiter NG OA?

oavoservice 提供 CodeSignal 内存数据库题型全流程辅助:Level 拆解、TTL 设计模板、Backup / Restore 快照算法。我们对 ZipRecruiter、Snowflake、Optiver 等 CodeSignal 系列公司的 4-Level 设计题有完整复盘,可以根据你的目标公司客制 OA 演练。

立即添加微信:Coding0201获取 ZipRecruiter OA 一对一辅导

#ZipRecruiter #ZipRecruiterOA #NewGrad #CodeSignal #内存数据库 #OA真题


联系方式

Email: [email protected]
Telegram: @OAVOProxy