找到两个数字桶之间的最短距离

Find a shortest distance between two buckets of numbers

本文关键字:之间 短距离 数字 两个      更新时间:2023-10-16

我有两个数字桶(无序,1 维数据结构),我想计算两个桶的任何元素之间的最小距离。有没有办法找到O(1)中不同存储桶中任何数字之间的最短距离?我最好的选择是什么?

Input
[B1] 1, 5, 2, 347, 50
[B2] 21, 17, 345
Output
2 // abs(347 - 345)

编辑

  • 我希望查找比插入更多
  • 任何桶中最小和最大元素之间的距离小于 10^5
  • 任何存储桶中的元素数小于 10^5
  • 存储桶中的数字"几乎"排序 - 这些是事件的时间戳。存储桶中可能有不到 1% 的元素
  • 出现故障 存储桶
  • 中的元素数量很少,但我需要以 2k/秒的平均速率查找,并定期删除过时的存储桶并用新存储桶替换它们,因此我希望我的查找处于O(1)

看看我为什么需要这个以及我在上一个问题版本中的想法。

总共有n个数字。
1.用二进制写所有数字。==> O(n)
2.在每个数字中附加 0 或 1,具体取决于是来自 B1 还是 B2。==> O(n)
3.快速排序它们,忽略第一点。 平均
==> O(n log n)4。 对于整个列表,循环访问排序顺序。对于每两个相邻的数字uv,如果它们同时来自B1或B2,则忽略。
否则,请在tmp > abs(u-v)时设置tmp <-- abs(u-v)。 因此,tmp是迄今为止相邻数字内的最小距离。
最后tmp是答案。==> O(n)

总计:平均==> O(n log n)

为每个存储桶创建一个包含 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。

edit如果元素没有上限为 10^5,而只是最小值和最大值之间的距离,则需要修改,但仍有效。如果这很重要,我可以详细说明必要的更改。

将存储桶插入两次 Y 快速尝试 (https://en.wikipedia.org/wiki/Y-fast_trie)。搜索最近的后继或前置是O(log log M),其中M是范围(实际上是max元素,但我们可以偏移),在您的情况下,上限约为四个操作。

由于您将存储最接近的差异,因此查找将O(1)(除非您每次都获得完整的存储桶而不是不断更新),而每个元素的插入、删除和更新将O(log log M)

这是我的尝试:对每个存储桶进行排序,然后对它们进行合并排序,以跟踪沿途的最小距离: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)

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,则必须存储i1i2mindist。假设存储桶B1,您可以在其中附加一个新元素。您对其进行排序并减少i2直到它0B2[i2] < B1[i1]。由于元素是时间戳,因此大多数时候最多只能是一步。然后再次运行 while 循环,通常也只有一个步骤。因此,k 个存储桶的计算复杂度为 O(k),内存复杂度为 O(k^2)。

我喜欢戴夫·高尔文的想法,稍微修改一下:

设 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)。我不知道这是否比对大桶或短桶进行分类更有效。

考虑预先计算两个列表中每个数字的答案并将它们存储为数组。 使用列表中每个数字的下标,并使用该下标下标到数组中包含差值的位置。

这给出了 O(1) 查找。