Netflix OA + 电面完整拆解 | Clarification 驱动的面试,题目难度不是筛选点

投的是 Netflix Member, Commerce & Games Engineering,这周刚面完。整个过程最大的感受就是:奈飞的面试形式和大多数科技公司完全不一样。题目本身不算难,甚至大都是 LeetCode Easy/Medium,但对沟通、思考过程和工程意识的要求异常严格。把 OA 和两轮店面的细节都记下来,希望对准备 Netflix 面试的人有帮助。

Netflix OA:CodeSignal 平台,三道题

奈飞走的是 CodeSignal,题目都是近期的新题,总共三道:一道概率 quiz,两道 coding。

题目 1:条件概率

场景:万圣节,三个朋友各拿到了不同数量的红、蓝、绿三种颜色糖果。给定表格:

  • Jack Silver:红 5、蓝 10、绿 2
  • Blake Smith:红 20、蓝 4、绿 4
  • Carrie Silver:红 12、蓝 6、绿 2

问题:如果你的姓是 Silver,你拿到蓝色糖果的概率是多少?

这题本质上就是考你会不会仔细读题。关键点是"姓 Silver 的人"------题目里有两个:Jack Silver 和 Carrie Silver,Blake Smith 不算。所以计算时只考虑这两个人的糖果:总数是 5+10+2+12+6+2 = 37,其中蓝色是 10+6 = 16,答案 16/37。

很容易出现的错误是:把 Blake 的数据也算进去,导致分母变成 51,答案错误。这题没什么数学难度,就是读题的细心程度。

题目 2:Bucket 文件系统模拟

题意:模拟一个虚拟环境里的简单文件系统,只有两个命令:

  • goto <bucket_name>:切换到指定 bucket(题目保证 bucket 存在)
  • create <filename>:在当前 bucket 创建一个文件(如果同名文件已存在,什么都不发生)

处理完所有命令后,返回文件数最多的 bucket 名字(题目保证无并列)。

一个例子的执行序列:

复制代码
goto bucketA
create fileA
create fileB
create fileA        # 同名,无效
goto bucketB
goto bucketC
create fileA
create fileB
create fileC

最终结果:bucketA 有 2 个文件,bucketB 空的,bucketC 有 3 个,所以返回 "bucketC"。

解法就是纯粹的数据结构模拟:用嵌套字典 + 集合来追踪每个 bucket 和其包含的文件。集合自动过滤重复,所以即使 create fileA 两次也只会存一份。

复制代码
def solution(commands):
    buckets = {}
    current = None
    
    for cmd in commands:
        action, name = cmd.split()
        if action == "goto":
            current = name
            buckets.setdefault(current, set())
        else:  # create
            buckets[current].add(name)
    
    return max(buckets, key=lambda b: len(buckets[b]))

这题有个隐藏坑:bucket 名和文件名可能重名(比如 bucket 叫 "bar",文件也叫 "bar"),但因为我们用集合按 bucket 隔离存储,天然没有问题。

数据规模最多 1000 个命令,时间复杂度 O(n),轻松通过。题目考的是你能不能清晰地用数据结构表达业务逻辑,难度不高但要实现清晰。

题目 3:Cyclic Pairs

这题比前两道有意思一点。

题意:cyclic shift 是把一个数末尾的若干位挪到开头。例如 546 的所有 cyclic shift 是:546、654、465。

给一个正整数数组,统计有多少对 (i, j)(其中 i<j),满足两个条件:

  1. 两数的位数相同
  2. ai 是 aj 的某个 cyclic shift(或反过来说,它们互为 cyclic shift)

例子:a = 13, 5604, 31, 2, 13, 4560, 546, 654, 456

答案是 5 对:

  • 13 和 31(互为 shift)
  • 13 和 13(位置 0 和 4)
  • 31 和 13(位置 2 和 0)
  • 5604 和 4560(互为 shift)
  • 546 和 654(互为 shift)

注意 546 和 456 不构成 pair,因为 456 不在 546 的 shift 集合里(546 的 shift 只有 546、654、465)。另外 4560 和 456 也不算,因为位数不同(一个 4 位,一个 3 位)。

朴素的解法是两两比较:对于每一对 (i, j),计算 aj 的所有 cyclic shift,看 ai 是否在其中。但数据规模是 10⁵,这样做是 O(n²) × O(d)(d 是数字位数),会超时。

正确思路是规范化 + 分组计数。核心想法是:一个数和它的所有 cyclic shift 本质上是"等价"的,我们可以给每个等价类选出一个"标准代表"。

最简单的选法是:对一个数 x,计算它的所有 cyclic shift,取其中字典序最小的那个作为 x 的"规范形"(canonical form)。然后统计数组里每个规范形出现了多少次,同一规范形的数两两构成一对。

复制代码
from collections import Counter

def solution(a):
    def canonical(x):
        s = str(x)
        # 生成所有 cyclic shift,取字典序最小
        return min(s[i:] + s[:i] for i in range(len(s)))
    
    # 计算每个数的规范形
    cnt = Counter(canonical(x) for x in a)
    
    # 同规范形的数两两配对,数量为 c*(c-1)/2
    return sum(c * (c - 1) // 2 for c in cnt.values())

时间复杂度分析:

  • 对每个数计算规范形:O(n × d²),其中 d ≤ 10(十进制数最多 10 位)
  • 计数和求和:O(n)
  • 总复杂度:O(n × 100),10⁵ 的数据完全可以接受

这题的关键洞察是意识到"cyclic shift 的等价性",进而转化成"规范形计数问题"。一旦想到这层,代码就很短了------这是算法题的常见套路。

电面第一轮:系统设计 + Clarification

题目名字非常简洁:"设计 Netflix 首页的去重逻辑"。但这里的"简洁"其实是陷阱------面试官给的需求极其 high level,几乎没有任何具体细节。

面试的对话过程

面试官:"Netflix 首页有很多内容。有时候同一部剧可能会出现在不同的推荐行里。我们希望确保用户看到的首页中,同一部剧不会出现两次。你怎么设计这个系统?"

乍一听是很直白的需求,但其实什么都没说清楚:

  • Input 是什么格式?是列表还是矩阵还是什么其他结构?
  • Output 要返回什么?是清理后的首页结构,还是去重后的剧名列表,还是别的?
  • "去重"的范围是什么?全页去重还是按行去重,还是有其他限制?
  • 是否需要保持原有的结构(行列关系),还是可以打乱顺序?

我用了大约 15 分钟和面试官反复确认:

我的理解是:首页是一个列表的列表(list of list),每个子列表代表一行可以横向滑动的推荐栏。每行里有多个剧名。整个首页需要去重,使得任何剧名在整个首页中只出现一次。Output 是清理后的相同结构(list of list)。

面试官确认了这个理解,但补充说:首页实际上可以竖向滑动也可以横向滑动,所以去重的方式要确保无论怎么滑都不会看到重复内容。

解法

思路其实很直接:维护一个 global visited set,记录整个首页里已经看到过的剧名。然后逐行遍历,对每一行里的剧名,只保留那些还没在 visited set 里的,同时把它们加入 visited set。

复制代码
def solution(homepage):
    global_visited = set()
    result = []
    
    for row in homepage:
        new_row = []
        for show in row:
            if show not in global_visited:
                new_row.append(show)
                global_visited.add(show)
        result.append(new_row)
    
    return result

代码写完后,面试官做的不是让我优化复杂度(这个已经是 O(n),无法优化),而是把话题转向现实场景。

Production 讨论:系统设计思考

面试官问:"这个设计在 Netflix 真实生产环境里能用吗?如果首页有 10 万部剧呢?或者 100 万?"

这时候本地缓存的 visited set 就成了瓶颈:

  • 如果剧库有百万级别,光存储已看过的剧 ID 就得占用大量内存
  • 分布式环境下,多个后端服务无法共享这个 set
  • 首页去重的逻辑可能在推荐系统、后端 API、前端等多个层次同时发生,需要一个统一的去重机制

于是我们讨论到了分布式解决方案:用 Redis bloom filter。Bloom filter 是一种概率数据结构,特别适合"检查元素是否出现过"这类场景:

  • 空间效率极高:百万级数据只需要几 KB 内存
  • 查询快速:O(1) 时间复杂度
  • 分布式友好:可以放在 Redis 等中央缓存里,多个服务共享

当然 bloom filter 有 false positive 风险(极小概率会说"没看过"的内容其实看过了),但对首页去重这个场景来说,偶尔重复一两个剧比多次询问数据库的成本低得多,这是一个可以接受的权衡。

这段对话让我意识到:Netflix 的"系统设计轮"不是传统的"设计一个分布式系统架构"类面试,而是直接让你从小问题延伸到真实业务问题。面试官不是在测你知不知道什么高深的理论,而是看你能不能:

  1. 从模糊的需求里问出关键细节
  2. 写出清晰、可运行的代码
  3. 自发地思考 scalability 和 production readiness
  4. 和面试官讨论权衡和优化策略

电面第二轮:Coding,围着去重继续

第二轮的三个 coding 题都围绕去重这个主题,难度从易到难。

题目 1:Contains Duplicate

最直接的版本。给一个列表(这轮的 input 是 show names),判断是否有重复。

复制代码
def hasDuplicate(shows):
    return len(shows) != len(set(shows))

这题本身没什么内容,就是考你能不能快速识别问题的本质并用最简洁的方式解决。面试官这里就是想让你热热手。

题目 2:最长无重复子列表

给一个 show name 列表,返回最长的连续子列表,其中没有重复的元素。这是 LeetCode 第 3 题(最长无重复子串)的列表版本。

例子:"A", "B", "C", "A", "D", "E" → 答案是 4,对应子列表 "B", "C", "A", "D""C", "A", "D", "E"

标准的 sliding window 做法:用两个指针 left 和 right,维护一个 window 内的集合,right 指针不断向右扩展,如果遇到重复元素就收缩 left 指针直到没有重复,同时记录最大的 window 宽度。

复制代码
def lengthOfLongestSubstring(shows):
    char_index = {}
    max_len = 0
    left = 0
    
    for right in range(len(shows)):
        if shows[right] in char_index and char_index[shows[right]] >= left:
            left = char_index[shows[right]] + 1
        char_index[shows[right]] = right
        max_len = max(max_len, right - left + 1)
    
    return max_len

时间复杂度 O(n),空间 O(min(n, 26))(对于字符串,字符集最多 26)。这题考的是你对 sliding window 这个经典套路的掌握程度。

题目 3:没有公共字符的 Unique Pair

给一个 show name 列表,找有多少对 shows,它们之间没有公共的字母(character)。返回 pair 的数量。

例子:"ab", "cd", "ac" → 答案是 1,只有 ("ab", "cd") 这一对没有公共字母。

朴素的做法是两两比较:对每一对,检查它们的字符集是否有交集。

复制代码
def countPairsWithoutCommonChar(shows):
    count = 0
    n = len(shows)
    for i in range(n):
        for j in range(i + 1, n):
            if not (set(shows[i]) & set(shows[j])):
                count += 1
    return count

时间复杂度 O(n² × k),k 是平均字符串长度。如果 n 和 k 都不太大,这个做法就足够了。当我现场写完这个解法后,面试官说"可以",没有要求优化。

但在讨论阶段,他提了一句可以用 bitmask 优化。思想是:把每个 show name 的字符信息压缩成一个 26 位的整数(用位掩码表示包含哪些字母),然后两个 mask 按位与(&)为 0 就表示没有公共字母。这样就不需要每次都做集合交集操作了。

复制代码
def countPairsWithoutCommonChar_optimized(shows):
    def char_mask(s):
        mask = 0
        for c in s:
            mask |= (1 << (ord(c) - ord('a')))
        return mask
    
    masks = [char_mask(show) for show in shows]
    count = 0
    n = len(shows)
    for i in range(n):
        for j in range(i + 1, n):
            if (masks[i] & masks[j]) == 0:
                count += 1
    return count

这个优化的好处是:每次 pair 检查只需要一个 bitwise AND 操作,比集合操作快。这是 LeetCode 318(单词破坏)问题的原型思想。

面试官这里其实就是在观察:你能不能识别出 optimization 的机会,以及知不知道用 bitmask 这样的技巧。但他不强求,因为题目规模不大的话,朴素解法也完全可以。

面试的整体感悟

经过这次面试,我对 Netflix 的筛选标准有了更清晰的理解。看似 easy/medium 的题目,其实考的是一整套工程思维:

  1. 沟通优先于优化 --- Netflix 更看重你能不能理解真实需求,而不是一上来就写 O(n log n) 的解法。题目模糊是有意的,目的就是看你会不会 clarify。

  2. 过程胜过结果 --- 即使你的代码有 bug,只要你的思考过程清晰、讨论态度认真,面试官通常会给高分。反过来,代码完美但闷头闷脑地写,分数会很低。

  3. 边界条件要主动覆盖 --- 写完代码后,不要等面试官问,主动提出空列表、全重复、单元素这些 edge case,并说明你会怎么处理。这样能展现出细致的工程意识。

  4. Production sense 很重要 --- 超过一定规模后,问题会升级。本地缓存不行了、得用分布式、得考虑成本和权衡。能自发地想到这些,或者至少在面试官引导下反应快,会显著提升面试分数。

  5. 不要过度优化 --- 如果题目规模不大,就不必非得用 bitmask 或其他 fancy 的技巧。清晰 + 正确 > 复杂 + 闪闪发光。面试官反而更欣赏"这个规模用简单方案,但我知道如果规模更大可以用 X 优化"这样的回答。

结语

Netflix 的面试让我重新思考了什么叫"好的工程师"。不是能解最难的 LeetCode,而是:

  • 敢于问问题
  • 能清晰地思考和表达
  • 主动考虑现实约束和边界情况
  • 知道什么时候简洁胜过聪慧

如果你正在准备 Netflix,与其狂刷 hard 题,不如找个 mock interview 的机会,和面试官一起讨论模糊需求的 clarification、production case 的权衡。这样才能真正理解 Netflix 的筛选标准。

相关推荐
众人皆醒我独醉6 小时前
Pod 一直 Terminating,死活删不掉?三个凶手,每一个你都意想不到
面试·kubernetes
凯瑟琳.奥古斯特8 小时前
力扣1009补码解法C++实现
开发语言·c++·算法·leetcode·职场和发展
KaifuZeng9 小时前
通信与接口协议面试十、PCIe
单片机·嵌入式硬件·面试·通信与接口协议
三月不知肉味y10 小时前
2026-07-05-JAVA面试场景题训练
java·开发语言·面试
qzhqbb12 小时前
字节面试分享复盘
面试·职场和发展
凯瑟琳.奥古斯特13 小时前
力扣1008:前序重建BST
开发语言·c++·算法·leetcode·职场和发展
未秃头的程序猿14 小时前
虚拟线程用了一年,我真香了——10倍吞吐量是真实存在的
java·后端·面试
帅次14 小时前
Android 高级工程师面试:Flow 与状态流 近1年高频追问 22 题
android·面试·职场和发展
贺国亚14 小时前
Harness-架构原理与工程实践
面试