我得到一个实数的数组,A。它有n + 1个元素。 众所周知,阵列x和y至少有2个元素,这样:
abs(x-y) <= (max(A)-min(A))/n
我需要创建一个算法,用于在O(n)时间内找到2个项目(如果有更多,任何一对是好的)。
我已经尝试了几个小时而且我被卡住了,有任何线索/提示吗?
答案 0 :(得分:8)
哇,我明白了!诀窍在于Pigeonhole Principle.
好吧..把数字想象成一条线上的点数。然后min(A)
和max(A)
分别定义该行的起点和终点。现在将该行划分为n
等长的(max(A)-min(A))/n
区间。由于有n+1
个点,因此其中两个必须属于其中一个区间。
请注意,我们不需要依赖于告诉我们有两个点符合标准的问题。 总是两个点满足它。
算法本身:您可以在这里使用简化形式的桶排序,因为每个桶只需要一个项目(点击两个就完成了)。首先循环遍历数组以获取min(A)
和max(A)
,并创建一个初始化为某个默认值的整数数组buckets[n]
,例如-1
。然后去第二遍:
for (int i=0; i<len; i++) {
int bucket_num = find_bucket(array[i]);
if (bucket[bucket_num] == -1)
bucket[bucket_num] = i;
else
// found pair at (i, bucket[bucket_num])
}
find_bucket(x)
返回x / ((max(A)-min(A))/n)
的向下舍入整数结果。
答案 1 :(得分:3)
让我们重新说出问题:我们要找到两个元素,例如abs(x-y) <= c
,其中c
是常量,我们可以在O(n)
时间找到它。 (实际上,我们可以在线性时间内计算max(A)
和min(A)
,只需指定c=(max-min)/n
)。
让我们假设我们有一组桶,因此在第一个桶元素0<=x<c
被放置,在第二个桶元素c<=x<=2c
被放置,等等。对于每个元素,我们可以确定它的桶O(1)
时间。请注意,占用的桶数不会超过数组中的元素数。
让我们迭代数组并将每个元素放到它的桶中。如果我们要放置它,那么已经存在另一个元素,那么我们刚刚找到了一对x
和y
!
如果我们迭代整个阵列并且每个元素都落入了它自己的桶中,不用担心!现在迭代存储桶(不超过n
存储桶,如上所述)和每个存储桶元素x
,如果在下一个存储桶y
中,则{ {1}},然后我们找到了解决方案。
如果我们迭代所有的桶并找不到合适的元素,那么就没有解决方案了。 OMG,我真的很想念那些信件(见the other answer)。
存储桶可以实现为哈希映射,其中每个存储桶包含一个数组索引(在存储桶中放置元素将如下所示:abs(x-y)<=c
)。我们在buckets[ a[i] / c] = i
时间内计算c
,在O(n)
时间内将项目分配给存储桶(O(n)*O(1)
是对哈希映射的访问权限),在O(1)
时间内遍历存储桶。因此,整个算法是线性的。