技术岗位 · Coding

数组区间是否全唯一:一次预处理,O(1)查询

保存每个右端对应的最早合法左端,查询只需比较边界。

题目重点:保存每个右端对应的最早合法左端,查询只需比较边界。

题意与假设

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

  • 数组静态、元素可哈希;query(l,r)为合法闭区间,单元素恒唯一。
  • 判断是否有任意重复,不要求输出重复项。

解题路线

  1. last[x]保存值x此前出现的最近下标。处理i时,所有以i结尾的唯一窗口左端必须>last[x]。
  2. 维护boundary=max(oldBoundary,last[x]+1),它是以i结尾无重复窗口的最小左端。保存left[i]。
  3. 查询[l,r]合法当且仅当l≥left[r]。因移除前缀不能引入重复,所有更靠右的左端都可行。

手动走一遍

[1,2,1,3]的left为[0,0,1,1];query(0,3)False,query(1,3)True。[7,7]的left[1]=1,因此全段False,但任一单点True。

Python 参考实现

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

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

class UniqueIndex:
    def __init__(self, a):
        self.n, self.left = len(a), []
        last, boundary = {}, 0
        for i,x in enumerate(a):
            boundary = max(boundary, last.get(x,-1)+1)
            self.left.append(boundary)
            last[x] = i

    def query(self,l,r):
        if not 0 <= l <= r < self.n:
            raise ValueError("invalid closed range")
        return l >= self.left[r]

复杂度

建表期望O(n)时间、O(n+d)空间,每query O(1)。动态更新会影响后续边界,不能沿用静态O(1)承诺。

易错点与追问

容易失分的边界

  • 把全局“值出现过两次”作为区间答案会误判只包含其中一次的查询。
  • last更新前必须用旧下标,否则boundary跳到i+1使单点也失败。

继续深挖

  • 需要区间不同值数量时,为什么一条left边界不够?
  • 动态point-update时可否用每值位置集合配合range-max结构?
✓已复制微信号!