题目重点:保存每个右端对应的最早合法左端,查询只需比较边界。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 数组静态、元素可哈希;query(l,r)为合法闭区间,单元素恒唯一。
- 判断是否有任意重复,不要求输出重复项。
解题路线
- last[x]保存值x此前出现的最近下标。处理i时,所有以i结尾的唯一窗口左端必须>last[x]。
- 维护boundary=max(oldBoundary,last[x]+1),它是以i结尾无重复窗口的最小左端。保存left[i]。
- 查询[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结构?
