Netflix 数据科学家面试实录 2026:真实面经完整复盘
Netflix面试第一人称完整复盘:涵盖算法Coding、系统设计、Behavioral面试。还原真实面试对话、高频题目与解题思路,附准备策略与注意事项,助你高效备战Netflix技术面试。
公司:Netflix 岗位:数据科学家 (Data Scientist) 面试形式:Virtual Onsite 结果:Pass → Offer
大家好,我是 Sam。这次分享我参加 Netflix DS 面试的完整经历。Netflix 的 DS 面试和其他大厂有一个很明显的区别:他们不太考传统意义上的 ML 建模题(比如手写梯度下降),而是更看重编码能力、系统设计思维、以及对数据如何驱动业务的理解。整场 VO 下来一共四轮,涵盖 Coding、System Design、Data Modeling 和 Behavioral,每一轮都有深度。
Coding:经典题变体,关键在扎实和表达
Coding 部分整体不难,基本都是经典题的变形。面试官给我出了一道 Command Undo System 的设计题。
题目还原:Command Undo System
题目描述:
设计一个支持 undo 操作的命令系统。要求:
- 执行命令(execute)
- 撤销最近一个命令(undo)
- 撤销最近一个带有特定 tag 的命令(undo_by_tag)
- 查询当前命令历史(get_history)
面试官:这个 undo system 的 tag 是怎么用的? 我:tag 是用来给命令分组的。比如一个用户可能执行了多个”保存”操作,每个”保存”都有一个 tag 叫 “save”。调用 undo_by_tag(“save”) 时,应该撤销最近一个带 “save” tag 的命令。 面试官:如果已经执行了普通的 undo,tag 索引需要更新吗? 我:需要。因为普通 undo 撤销的是栈顶的命令,如果这个命令有 tag,我们需要从对应的 tag 列表中移除它。
from collections import defaultdict
from dataclasses import dataclass, field
from typing import Optional
import time
@dataclass
class Command:
"""单个命令"""
cmd_id: str
action: str
tag: str
timestamp: float
is_executed: bool = True
class CommandUndoSystem:
"""
支持按 tag 回滚的命令系统。
数据结构设计:
- command_stack: 所有命令的执行顺序栈
- tag_commands: tag -> 该 tag 下的命令列表(栈)
时间复杂度:
- execute: O(1)
- undo: O(1)
- undo_by_tag: O(1) 均摊
- get_history: O(n)
"""
def __init__(self):
self.command_stack: list[Command] = []
self.tag_commands: dict[str, list[Command]] = defaultdict(list)
def execute(self, action: str, tag: str = "") -> str:
"""执行一个命令"""
cmd_id = f"cmd_{len(self.command_stack) + 1}"
cmd = Command(
cmd_id=cmd_id,
action=action,
tag=tag,
timestamp=time.time()
)
self.command_stack.append(cmd)
if tag:
self.tag_commands[tag].append(cmd)
return cmd_id
def undo(self) -> Optional[Command]:
"""撤销最近一个命令"""
if not self.command_stack:
return None
cmd = self.command_stack.pop()
cmd.is_executed = False
if cmd.tag and cmd in self.tag_commands.get(cmd.tag, []):
self.tag_commands[cmd.tag].pop()
return cmd
def undo_by_tag(self, tag: str) -> Optional[Command]:
"""撤销最近一个带指定 tag 的命令"""
if not self.tag_commands.get(tag):
return None
# 找到最近一个带该 tag 的命令
target_cmd = self.tag_commands[tag].pop()
# 从主栈中移除
self.command_stack = [
c for c in self.command_stack if c.cmd_id != target_cmd.cmd_id
]
target_cmd.is_executed = False
return target_cmd
def get_history(self) -> list[Command]:
"""获取已执行的命令历史"""
return [c for c in self.command_stack if c.is_executed]
面试官追问:
面试官:undo_by_tag 的时间复杂度是多少? 我:当前实现中,从 command_stack 里移除一个元素的复杂度是 O(n),因为需要遍历列表。如果要优化到 O(1),可以用 doubly linked list 代替 list,每个 Command 存储 prev/next 指针。这样删除操作只需要修改前后指针。 面试官:好,那如果用 linked list,tag_commands 里的引用还能直接指向节点吗? 我:可以。tag_commands 里存的是节点的引用,不是索引。所以从 tag 栈弹出后,拿到的是节点引用,直接在 linked list 上做 remove 就是 O(1)。
拓扑排序变体
另一轮 coding 出了拓扑排序,但是加了约束。
import heapq
from collections import defaultdict, deque
def topological_sort_all(graph: dict[str, list[str]],
all_nodes: list[str]) -> list[list[str]]:
"""
输出所有可能的拓扑排序结果。
使用 DFS + 回溯,比 Kahn 算法更适合枚举所有结果。
时间复杂度: O(N! * V),N 是节点数
空间复杂度: O(V)
"""
adj = defaultdict(list)
in_degree = defaultdict(int)
for node in all_nodes:
in_degree[node] = 0
for node, neighbors in graph.items():
for neighbor in neighbors:
adj[node].append(neighbor)
in_degree[neighbor] += 1
results = []
def dfs(path, remaining_in_degree):
if len(path) == len(all_nodes):
results.append(path[:])
return
for node in all_nodes:
if node not in path and remaining_in_degree[node] == 0:
# 选择该节点
path.append(node)
# 更新入度
for neighbor in adj[node]:
remaining_in_degree[neighbor] -= 1
dfs(path, remaining_in_degree)
# 回溯
path.pop()
for neighbor in adj[node]:
remaining_in_degree[neighbor] += 1
dfs([], dict(in_degree))
return results
面试官:如果图很大,所有拓扑排序的结果可能非常多,有优化方法吗? 我:有几个方向:
- 限制输出数量:只返回前 K 个结果,用 BFS 按优先级扩展。
- 字典序要求:如果要求按字典序输出,可以用最小堆代替遍历所有节点。
- 流式输出:不一次性生成所有结果,用 generator 按需产出。
System Design:考察深度,而不是框架
System Design 这一轮我遇到的题目是设计一个推荐系统的后端服务。
架构设计:Netflix 推荐系统简化版
面试官:请你设计一个视频推荐系统。用户打开 Netflix 首页时,需要展示一排排推荐视频。 我:好的。我先确认几个关键指标:
- DAU 大概多少?假设 2 亿
- 每个用户看到多少个推荐?假设 10 排 × 每排 15 个 = 150 个推荐
- P99 延迟要求?假设 < 500ms
- 推荐需要实时更新还是离线计算?
系统架构:
┌─────────────┐
│ Client App │
└──────┬──────┘
│ REST API
▼
┌─────────────────────────┐
│ API Service │
│ (聚合层 / BFF) │
└──┬──────────┬──────────┬┘
│ │ │
▼ ▼ ▼
┌────────────┐ ┌─────────┐ ┌──────────────┐
│ Candidate │ │ Ranking │ │ Personalized │
│ Generation │ │ Service │ │ Cache (Redis)│
└─────┬──────┘ └────┬────┘ └──────────────┘
│ │
▼ ▼
┌──────────────────────────────────┐
│ Feature Store │
│ (用户特征 + 内容特征 + 交互特征) │
└──────────────────────────────────┘
│
▼
┌──────────────────────────────────┐
│ Offline Pipeline │
│ Spark / Flink 模型训练 + 特征计算 │
└──────────────────────────────────┘
面试官:Candidate Generation 和 Ranking 的 trade-off 是什么? 我:Candidate Generation 负责从海量内容中快速筛出几百个候选,速度优先,精度可以稍低。常用方法包括协同过滤、Embedding-based retrieval。Ranking 负责精细排序,对候选做更复杂的特征计算和模型打分,精度优先,但输入量已经缩减到几百,所以可以用更重的模型。
Data Modeling:从结构到理解
Data Modeling 这一轮,面试官让我设计一个用户行为追踪的数据库 schema。
-- 用户行为事件表
CREATE TABLE user_events (
event_id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
event_type VARCHAR(50) NOT NULL, -- play, pause, resume, rate, etc.
content_id BIGINT NOT NULL, -- 视频/电影 ID
event_ts TIMESTAMP NOT NULL,
device_type VARCHAR(20),
session_id VARCHAR(64),
watch_duration_ms INT, -- 观看时长
completion_pct DECIMAL(5,2), -- 完成百分比
INDEX idx_user_time (user_id, event_ts),
INDEX idx_content (content_id),
INDEX idx_event_type (event_type, event_ts)
) PARTITION BY RANGE (UNIX_TIMESTAMP(event_ts)) (
PARTITION p202505 VALUES LESS THAN (UNIX_TIMESTAMP('2025-06-01')),
PARTITION p202506 VALUES LESS THAN (UNIX_TIMESTAMP('2025-07-01'))
);
-- 用户画像表(离线聚合)
CREATE TABLE user_profiles (
user_id BIGINT PRIMARY KEY,
total_watched_hours DECIMAL(10,2),
favorite_genres JSON, -- {"drama": 0.8, "comedy": 0.3}
avg_completion_rate DECIMAL(5,4),
last_active_ts TIMESTAMP,
updated_at TIMESTAMP
);
面试官:为什么用 JSON 存 favorite_genres 而不是单独的表? 我:因为 genre 偏好是一个稀疏向量,每个用户的活跃 genre 数量不同。用 JSON 可以灵活存储,不需要预定义列。同时查询时可以直接在应用层解析,避免 JOIN 开销。但如果需要按 genre 做聚合查询,可能需要额外建立 genre 倒排索引。
Behavioral:看起来简单,其实最有决定性
Behavioral 有两轮,面试官都是 senior 级别。问题很常规,但考察点很明确:你是否和团队匹配。
面试官:Tell me about a time you dealt with ambiguous requirements. 我:(用 STAR 框架讲述了一个项目经历,强调如何主动定义问题、收集 stakeholder 反馈、快速迭代方案) 面试官:你当时是怎么决定优先级的? 我:我用了一个简单的 impact/effort 矩阵,把需求分成了四个象限。和 PM 对齐后,先做高影响低投入的 quick win,建立信心后再投入大项目。
面试总结
成功经验
- 编码要扎实:Netflix 的 coding 不考偏题,但要求代码质量高、边界情况覆盖全。
- System Design 要深入:不要只画架构图,要深入到具体的 trade-off 和实现细节。
- Behavioral 要主动:不要被动回答,要主动展示决策过程和影响力。
- Data Modeling 要有业务思维:不仅考虑 schema 设计,还要考虑数据如何流动、如何被消费。
面试注意事项
时间管理:每轮 45-60 分钟,coding 35 分钟 + 讨论 10 分钟。System Design 5 分钟需求分析 + 10 分钟架构 + 25 分钟深入。
技术深度:Netflix 的面试官非常看重你对技术的深入理解。不要只说”用什么”,要说”为什么用”和”为什么不选别的”。
推荐阅读
- Netflix 面试全流程指南 — Netflix 面试流程、高频题目与准备策略
- System Design 面试完全攻略 — 分布式系统设计的核心原则与高频题目
- 行为面试 STAR 故事模板 — Leadership、决策、冲突解决等高频行为问题的回答框架
💡 需要面试辅导?
如果你对准备技术面试感到迷茫,或者想要个性化的面试指导和简历优化,欢迎联系 Interview Coach Pro 获取一对一辅导服务。
👉 联系我们 获取专属面试准备方案