我有两个数字桶(无序,1维数据结构),我想计算两个桶中任何元素之间的最小距离。有没有办法找到O(1)
中来自不同桶的任何数字之间的最短距离?什么是我最好的选择?
Input
[B1] 1, 5, 2, 347, 50
[B2] 21, 17, 345
Output
2 // abs(347 - 345)
编辑
O(1)
在previous question edition中了解我为什么需要这个和我想到的。
答案 0 :(得分:1)
这是我的尝试:对每个桶进行排序,然后将它们合并,以便跟踪沿途的最小距离:O(n+2.n/2.ln(n/2)) = O(n.ln(n))
:
sort buk1
sort buk2
min = INT_MAX
last = some value
do
if top(buk1) > top(buk2)
min = min(min, abs(top(buk1) - last))
last = top(buk1)
pop(buk1)
else
min = min(min, abs(top(buk2) - last))
last = top(buk2)
pop(buk2)
while !empty(buk1) and !empty(buk2)
答案 1 :(得分:1)
总共有n
个数字
1.用二进制编写所有数字。 ==> O(n)
2.根据是B1还是B2,在每个数字中附加0或1。 ==> O(n)
3.嘲笑他们,忽略第一位。平均==> O(n log n)
个
4.对于整个列表,迭代排序顺序。对于每两个相邻的数字u
和v
,如果它们来自B1或B2,则忽略。
否则,只要tmp <-- abs(u-v)
设置tmp > abs(u-v)
。
因此,tmp
是目前为止在相邻数字内的最小距离
最后的tmp
就是答案。 ==> O(n)
总计:==> O(n log n)
平均
答案 2 :(得分:1)
O(1)当然是不可能的。
一些伪代码,我将其作为起点:
sort(B1)
sort(B2)
i1 = 0
i2 = 0
mindist = MAX_INT
// when one of the buckets is empty, we'll simply return MAX_INT.
while(i1 < B1.size() && i2 < B2.size())
t = B1[i1] - B2[i2]
mindist = min(mindist, abs(t))
if t > 0
i2 ++
else
i1 ++
return mindist
至少那是O(n log n),因为它在开头的排序中占主导地位。如果您的存储桶已经排序,则可以使用O(n)。
修改强>
在新信息之后,元素几乎已经排序,我建议在插入时对它们进行实际排序。使用二进制搜索的插入排序不是最适合这种情况的。只需附加新元素并将其交换,直到它适合。通常它不会掉期而且对于1%,你需要互换,99%的时间它只有一个。最坏的情况复杂度为O(n),但平均值几乎为O(1)。
如果您考虑为所有存储桶对预先计算mindist
,则必须存储i1
和i2
以及mindist
。假设B1
是存储桶,您可以在其中追加新元素。您可以对其进行排序并缩小i2
,直到它为0
或B2[i2] < B1[i1]
。由于元素是时间戳,因此大多数情况下最多只能执行一个步骤。然后再次运行while循环,通常只会执行一个步骤。因此k桶的计算复杂度为O(k),存储器复杂度为O(k ^ 2)。
答案 3 :(得分:1)
为每个存储桶创建一个10 ^ 5个元素的位向量。跟踪最小距离(最初10 ^ 5,直到两个桶都是非空的)。
现在,假设您正在向其中一个存储桶添加元素x。执行以下操作:
1. Set the bit x of the same bucket.
2. Check whether the other bitvector has any set elements within min_distance-1 of x
3. Update min_distance as appropriate
运行时间:在插入O(min_distance)时,技术上是O(1),因为min_distance是上限的。在轮询它的O(1)因为你刚刚返回min_distance。
编辑如果元素的上限不是10 ^ 5,而只是最小值和最大值之间的距离,则需要修改但仍然有效。如果这很重要,我可以详细说明必要的变化。
答案 4 :(得分:1)
将您的存储桶插入两次Y-fast尝试(https://en.wikipedia.org/wiki/Y-fast_trie)。搜索最近的继任者或前任是O(log log M)
,其中M
是范围(实际上是最大元素,但我们可以抵消),在您的情况下,它将限制在大约四个操作。
由于您将存储最近的差异,因此查找将为O(1)
(除非您每次都获得完整的存储桶而不是不断更新),而每个元素的插入,删除和更新将为O(log log M)
答案 5 :(得分:0)
我喜欢Dave Galvin的想法,略有修改:
设maxV为元素的最大数量maxV = max(bucket1.size,bucket2.size)
1。构建两个数组,每个数组的大小为maxV。填写他们:
for (j=0 to bucket1.size)
array1(bucket1(j)) = bucket1(j)
for (j=0 to bucket2.size)
array2(bucket2(j)) = bucket1(j)
现在对数组进行排序。数组中的其余元素为0。
2。现在使用两个迭代器,每个数组一个:
it1 = array1.begin
it2 = array2.begin
while (it1 == 0)
++it1
while (it2 == 0)
++it2
minDist = abs(it1-it2)
while (it1 != array1.end && it2 != array2.end)
{ //advance until overpass the other
while (it1 <= it2 && it1 != array1.end)
++it1
if (it1 > 0)
check minDist between it1, it2
while (it2 <= it1 && it2 != array2.end)
++it2
if (it2 > 0)
check minDist between it1, it2
if (it1 = it2)
//well, minDist = 0
return now
}
步骤1是O(n)。步骤2也是O(n)。我不知道这是否比为大桶或短桶分拣铲斗更有效。
答案 6 :(得分:0)
考虑为两个列表中的每个数字预先计算答案,并将它们存储为数组。使用列表中每个数字的下标,并使用它下标到数组中包含差异的位置。
这给了O(1)查找。