Member / SWE · VO Coding / Phone Screen 变体

Netflix 最长连续无重复 Show:滑窗到 Last Seen 跳指针

从 Netflix Coding 长帖的错误版本和最终版本出发,解释先检查再加入、窗口左边界为何不能倒退,并返回最早的最长无重复子数组。

题目重点:从 Netflix Coding 长帖的错误版本和最终版本出发,解释先检查再加入、窗口左边界为何不能倒退,并返回最早的最长无重复子数组。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 输入元素可哈希;返回最长连续无重复的实际 slice,长度相同取最早出现的 slice。题目长帖返回 list,但平局规则未给。
  • 空输入返回空 list;show ID 的相等语义已经确定。
  • 本题要求连续子数组,不是任意去重后保留的子序列。

解题路线

  1. set 滑窗:右端新 show 已在 set 时,从左侧逐个删除直到重复消失,然后加入新 show;每个元素最多入/出一次。先 add 再判断会让新 show 立刻命中,正是长帖记录的 bug。
  2. last-index 优化:记录每个 show 上次位置;只有上次位置仍在当前窗口内,才把 left 跳到 `last+1`,用 `max(left,last+1)` 的含义保证 left 不倒退。
  3. 每步比较当前窗口长度;只有严格更长才保存 best_start/best_length,使并列时保留最早。最终切片一次返回,避免每次改善都复制整个窗口造成 O(n²) 输出开销。

手动走一遍

[A,B,C,A,D] 扫到第二个 A 时,上次 A 在下标 0,left 从 0 跳到 1,当前窗口 [B,C,A];再加 D 得 [B,C,A,D],返回长度 4 的 slice。若之后遇到很早已滑出窗口的元素,不应把 left 往回拉。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

def longest_unique_contiguous(shows):
    """Return earliest longest contiguous slice with distinct show IDs."""
    last_index = {}
    left = 0
    best_start = 0
    best_length = 0
    for right, show in enumerate(shows):
        if show in last_index and last_index[show] >= left:
            left = last_index[show] + 1
        last_index[show] = right
        length = right - left + 1
        if length > best_length:
            best_start, best_length = left, length
    return shows[best_start:best_start + best_length]

复杂度

遍历 n 次,哈希操作预期 O(1),最后只复制一次最优 slice O(n),总预期 O(n) 时间;last-index 最多保存不同 show 数 D,空间 O(D),输出至多 O(n)。

易错点与追问

容易失分的边界

  • 把右端元素先加进 visited 再检查是否已存在,必然自撞。
  • 重复位置已在窗口左侧仍让 left 后退。
  • 每次更新最优都切片复制,最坏退化为 O(n²)。
  • 把连续无重复子数组当可跳过中间重复项的子序列。
  • 用长度相等时也更新结果,悄悄改成取最晚解。

继续深挖

  • 若只求长度而不返回 slice,可否减少输出拷贝?
  • 如果 ID 是复杂对象不可哈希,如何定义稳定键?
  • 输入无限流且要报告最近 W 项内最长无重复段时需要什么过期处理?
✓已复制微信号!