以下是一位朋友被问到的面试问题。我们都难过了。声明如下:
考虑一个未排序的整数列表
A
。假设A
的大小为n
。进一步假设索引i
处的元素具有值x
。我们定义了两个术语:如果值
A
位于k
中的任何一个,则- 如果
x
在索引范围A[i-k], A[i-k+1],...,A[i-1],A[i+1],...,A[i+k]
中有“重复”(即k
是跨指标搜索的半径)A
的任何元素位于d
范围内,则{li>
A
的“值范围x-d, x-d+1,...,x,x+1,...,x+d
重复”(即d
为跨值搜索的半径)在O(n)时间和O(k)空间中,我们想知道:
A
在索引范围k
中是否有重复?- 醇>
A
索引范围k
和值范围d
是否重复?
第一个很简单:我们从索引0
走到n-1
并保留一组我们见过的k
个数字。如果我们在添加之前我们当前的数字已经在集合中,那么我们就有了重复数据。否则我们不会,并且我们删除集合中最旧的元素以为新的元素腾出空间。
第二个,我不知道。我可以想到O(nd)时间和O(k)空间中的解决方案:保持与第一个问题相同的设置,但是,当我们点击x
时,检查{{1}之间的每个数字}和x-d
。但我无法想象在空间或时间复杂度方面没有x+d
的解决方案会是什么样子。我错过了什么?
答案 0 :(得分:6)
您可以通过扩展第一种方法来完成第二部分。
不是将原始值存储在集合中,而是使用字典并存储除以d + 1的值(映射到实际值)。
重点是我们可以确定没有2个值可以位于同一个bin中(或者它们比d更接近)。
现在,当您扫描时,您需要检查垃圾箱中的可能碰撞以及两个相邻的垃圾箱。
所以这是O(3n)= O(n)运算和O(k)空间。
def check_for_duplicate(A,d,k):
D = {} # Stores the previous 2k entries
for i,a in enumerate(A):
b = a // (d+1)
for delta in [-1,0,1]:
if b+delta in D and abs(D[b+delta] - a) <= d:
return True
old = i - 2 * k
if old >= 0:
del D[ A[old] // (d+1) ]
D[b] = a
return False
print check_for_duplicate(A=[8,14],d=5,k=2)
答案 1 :(得分:1)
所以它发生在我身上,你可以做到
part1 = false;
part2 = false;
for (index = i - k; index <= i + k, index++) {
diff = ABS(A[index] - x);
if (diff == 0) { part1 = true; }
if (diff < d) { part2 = true; }
}
(不是在python中,但算法似乎已经足够了)让我知道如果我完全忽略了这一点,那就太晚了。