Meta SDE VO 全流程面经 2026 | 3轮Coding+Behavioral+系统设计详细解析

Meta SDE VO 面试结构:两天完成五轮,涵盖三轮编码、一轮行为面试、一轮系统设计。
Meta VO 面试总览
2025 年下半年开始,Meta 的 SDE VO(Virtual Onsite)面试流程趋于稳定:3 轮 Coding + 1 轮 Behavioral + 1 轮 System Design,通常分两天进行,全部线上。Coding 轮使用 CoderPad 编写代码,System Design 使用 Excalidraw 画图。
和其他大厂不同的是,Meta 的 Coding 轮不要求代码真正运行通过测试——面试官更看重你的思考过程、dry run 的严谨性,以及边界条件的覆盖。这意味着你不能只靠 ChatGPT 生成答案混过去,因为面试官一定会要求你一行一行走逻辑。
Round 1:Coding — Trie + DFS 搜索(Word Search II 变种)
题目描述
输入一个字符矩阵(m × n)和一个单词列表,要求返回所有可以在矩阵中找到的单词。路径可以上下左右移动,但不能重复使用同一个位置。
约束条件:
- 矩阵大小最大 12 × 12
- 单词列表最多 10,000 个
- 单词长度不超过 10
解法 1:纯 DFS 暴力(会超时)
对每个单词单独进行 DFS 搜索,时间复杂度为 O(W × m × n × 4^L),其中 W 是单词数量,L 是单词长度。当 W 很大时完全不可接受。
解法 2:Trie 前缀树 + DFS(推荐)
核心思路:把所有目标单词构建成一棵 Trie 前缀树,然后在矩阵上只做一次 DFS。每当 DFS 路径对应的前缀不在 Trie 中时,直接 prune,不再继续搜索。
class TrieNode:
def __init__(self):
self.children = {}
self.is_word = False
def buildTrie(words):
root = TrieNode()
for word in words:
node = root
for ch in word:
if ch not in node.children:
node.children[ch] = TrieNode()
node = node.children[ch]
node.is_word = True
return root
def wordSearchII(board, words):
root = buildTrie(words)
m, n = len(board), len(board[0])
found = set()
def dfs(r, c, node, path):
if (r, c) in visited:
return
ch = board[r][c]
if ch not in node.children:
return
visited.add((r, c))
node = node.children[ch]
path.append(ch)
if node.is_word:
found.add(''.join(path))
for dr, dc in [(0,1),(0,-1),(1,0),(-1,0)]:
nr, nc = r+dr, c+dc
if 0 <= nr < m and 0 <= nc < n:
dfs(nr, nc, node, path)
path.pop()
visited.remove((r, c))
visited = set()
for i in range(m):
for j in range(n):
dfs(i, j, root, [])
return list(found)
复杂度分析:
- 时间:O(m × n × 4^L),但实际被 Trie 大幅 prune,远优于暴力
- 空间:O(W × L) 构建 Trie + O(L) 递归栈深度
第二题:Search in Rotated Sorted Array
经典二分查找变种。数组原本升序排列,然后在某个未知点旋转。要求 O(log n) 时间找到 target。
def searchRotated(nums, target):
lo, hi = 0, len(nums) - 1
while lo <= hi:
mid = (lo + hi) // 2
if nums[mid] == target:
return mid
if nums[lo] <= nums[mid]: # left half is sorted
if nums[lo] <= target < nums[mid]:
hi = mid - 1
else:
lo = mid + 1
else: # right half is sorted
if nums[mid] < target <= nums[hi]:
lo = mid + 1
else:
hi = mid - 1
return -1
复杂度:时间 O(log n),空间 O(1)。
Round 2:Coding — Sliding Window + Hard 图论
第一题:至多 K 个不同字符的最长子串(返回子串内容)
LeetCode 159 的变种——不仅要返回长度,还要返回实际子串。
def longestSubstrKChars(s: str, k: int) -> str:
if k == 0:
return ""
freq = {}
left = 0
best = ""
for right, ch in enumerate(s):
freq[ch] = freq.get(ch, 0) + 1
while len(freq) > k:
freq[s[left]] -= 1
if freq[s[left]] == 0:
del freq[s[left]]
left += 1
if right - left + 1 > len(best):
best = s[left:right+1]
return best
面试官常见追问:
- 为什么频次为 0 的字符需要移出 hash table?(否则
len(freq)不准确) - Unicode 字符怎么处理?(Python 天然支持,但 Java 中要注意 char vs code point)
- 可以用
collections.Counter替代 dict 吗?(可以,但len()统计的是含零值的 key 数量,需要额外过滤)
第二题:Shortest Distance from All Buildings(Hard)
给定一个网格,包含空地、障碍物和建筑,要求找到距离所有建筑之和最小的空地。
from collections import deque
def shortestDistance(grid):
if not grid or not grid[0]:
return -1
m, n = len(grid), len(grid[0])
dist = [[0]*n for _ in range(m)]
reach = [[0]*n for _ in range(m)]
buildingCount = 0
for i in range(m):
for j in range(n):
if grid[i][j] == 1:
buildingCount += 1
queue = deque([(i, j, 0)])
visited = [[False]*n for _ in range(m)]
visited[i][j] = True
while queue:
r, c, d = queue.popleft()
for dr, dc in [(0,1),(0,-1),(1,0),(-1,0)]:
nr, nc = r+dr, c+dc
if 0 <= nr < m and 0 <= nc < n and not visited[nr][nc] and grid[nr][nc] == 0:
visited[nr][nc] = True
dist[nr][nc] += d + 1
reach[nr][nc] += 1
queue.append((nr, nc, d + 1))
minDist = float('inf')
for i in range(m):
for j in range(n):
if grid[i][j] == 0 and reach[i][j] == buildingCount:
minDist = min(minDist, dist[i][j])
return minDist if minDist != float('inf') else -1
复杂度:时间 O(B × m × n)(B 为建筑数量),空间 O(m × n)。
Round 3:Coding — BFS 状态搜索
第一题:最短状态转换路径
给定初始状态、目标状态和合法转换规则(+1, -1, ×2, ÷2),求最短转换路径。
from collections import deque
def shortestTransformation(start, target, maxVal):
if start == target:
return 0
visited = {start}
queue = deque([(start, 0)])
while queue:
state, steps = queue.popleft()
candidates = [state + 1, state - 1, state * 2]
if state % 2 == 0:
candidates.append(state // 2)
for next_state in candidates:
if 0 <= next_state <= maxVal:
if next_state == target:
return steps + 1
if next_state not in visited:
visited.add(next_state)
queue.append((next_state, steps + 1))
return -1 # unreachable
面试官追问:状态空间特别大时如何防止 OOM?
- 加边界条件(maxVal)
- 使用 lazy visited marking(入队时不标记,出队时才标记),但会允许重复入队,需要权衡
- 双向 BFS 从两端同时搜索
第二题:Product of Two Run-Length Encoded Arrays
LeetCode 原题,核心思路是双指针遍历两个编码数组,对每个重叠区间逐元素相乘,再合并连续相同值的区间。
def findRLEArray(encoded1, encoded2):
def expand(encoded):
result = []
for val, freq in encoded:
result.extend([val] * freq)
return result
arr1, arr2 = expand(encoded1), expand(encoded2)
product = [a * b for a, b in zip(arr1, arr2)]
# Re-encode
result = []
i = 0
while i < len(product):
j = i
while j < len(product) and product[j] == product[i]:
j += 1
result.append([product[i], j - i])
i = j
return result
Round 4:Behavioral
面试官是 TPM,问题围绕 Conflict Resolution、Decision Making 和 Leadership 展开。
典型问题与回答框架
Meta 的行为面试基于其 Core Principles:
| 原则 | 考察维度 | STAR 框架应用 |
|---|---|---|
| Move Fast | 执行力和优先级判断 | 举例说明如何在模糊需求下快速推进 |
| Focus on Impact | 结果导向 | 量化你的贡献和对业务的影响 |
| Be Authentic | 诚实与自我认知 | 分享一个失败经历及事后复盘 |
| Build with Diversity | 跨团队协作 | 描述如何解决跨团队资源冲突 |
高频问题示例
"Tell me about a time you had to push a schema change but backend resources were delayed."
- Situation:数据库 schema 变更影响 3 个服务,但后端团队排期已满
- Task:确保变更在 release window 前完成
- Action:主动发起三方 meeting,重新评估 scope,将变更拆分为 two-phase migration,先上线兼容层
- Result:延期从 2 周缩短到 3 天,所有服务平滑迁移
Round 5:System Design — Real-time Notification System

Word Search II 算法选择:Trie + DFS 对比暴力搜索的复杂度优势。
需求
设计一个实时通知系统,支持:
- 海量用户 subscribe/unsubscribe
- 低延迟推送(< 1s P99)
- 多端支持(Web / iOS / Android)
- 高可用和水平扩展
系统架构
┌──────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────────┐
│ Producer │────▶│ Kafka │────▶│ Dispatcher │────▶│ Device │
│ (Event │ │ Message Queue│ │ (Stateless, │ │ Registry │
│ Source) │ │ (Partitioned)│ │ Scalable) │ │ (Redis) │
└──────────┘ └──────────────┘ └──────────────┘ └────────────┘
│
▼
┌────────────┐
│ Delivery │
│ Tracker │
│ (Postgres) │
└────────────┘
核心设计决策:
- Kafka 作为消息队列:支持 partition 持久化,consumer group 自动负载均衡
- Dispatcher 无状态设计:可以无限水平扩展,利用 Kafka consumer group 控制并发
- Device Registry 存 Redis:记录每个用户的活跃设备列表,读写 O(1)
- Delivery Tracker 用 Postgres:持久化投递状态,支持重试和去重
面试官追问方向:
- Kafka partition 数量如何确定?(根据吞吐量 = QPS × 消息大小 ÷ 单 partition 吞吐上限)
- 用户设备离线时的 fallback 策略?(push notification via APNs/FCM)
- 如何保证 exactly-once 投递?(idempotent key + deduplication table)
面试经验总结
- Meta 的 Coding 轮核心不是"写出代码",而是"证明你的代码正确"——dry run 是必考题
- Tag 题积累至关重要:区间、排序、图论、滑动窗口、二分查找、Trie、BFS 是高频考点
- Behavioral 准备 Meta Core Principles,每个原则至少准备 2 个 STAR 故事
- System Design 考察深度优先于广度——选一个模块讲透比泛泛而谈更好
- Follow-up 是区分线——面试官不会满足于标准解法,一定会追问优化方案
💡 如果你正在准备 Meta 的 VO 面试,想要一次免费的 mock 面试体验,或者需要专业的VO 代面 / 面试辅助服务,欢迎联系我们的技术团队:
👉 立即预约免费咨询
© 2026 interview-help.live — 专业 SDE 面试辅助平台