用于查找集合中下一个最小和最大数字的快速算法

时间:2009-05-24 04:47:58

标签: algorithm language-agnostic datetime hash dataset

我有一组正数。给定一个不在集合中的数字,我想找到集合中 的下一个最小和下一个最大数字。我现在能想到的唯一方法就是通过减少1找到下一个最小值,直到我在集合中找到一个数字,然后再找到下一个最大值。

动机:我在hashmap中有一堆数据,按日期键入。我没有每个日期的数据点。如果我有数据,例如,10/01/2000为60和10/05/2000为68,我要求10/02/2000,我想要线性插值。我应该得到62.

9 个答案:

答案 0 :(得分:4)

这取决于您的设置是否已排序。

如果您的集合未排序,那么找到最接近的(更高和更低)是O(n)操作和相当简单的算法。

如果您的集合已经排序,那么您可以使用修改后的二分搜索来找到O(log n)中的答案,这显然要好得多,特别是在较大的集合上。

如果您反复执行此操作,则可能需要对集合进行排序,这会导致O(n log n)成本可能一次性关闭或不取决于集合更改的频率。随着新项目的添加,某种树种排序可能有助于改善未来的排序。

答案 1 :(得分:3)

所有这些归结为binary search,前提是您可以对数据进行排序。有两种选择。

  1. 已分类的容器
    如果将数字保存在已排序的容器中,这非常简单。而不是使用HashMap,将数据放在TreeMap中,然后您可以有效地找到下一个较低或较高的元素。 Java甚至可以使用您想要的方法:

    这很有效,因为TreeMap在内部使用了red-black tree(一种balanced binary search tree)。 higherKeylowerKey只需从根开始并遍历树以查找元素应该去的位置。

    我不确定你使用的语言是什么,但在C ++中你会使用std::map,类似的方法是:

    • iterator lower_bound(const key_type& k)
    • iterator upper_bound(const key_type& k)
  2. 数组+排序
    如果您不想一直对数据进行排序,您可以随时将数据转储到数组(或任何随机访问容器)中,使用sort,然后在阵列上使用STL的二进制搜索例程:

    在Java中,模拟将把事物转储到ArrayList,调用Java sort(),然后使用binarySearch()

  3. 此处的所有搜索例程都是 O(logn)时间。使用已排序的容器或使用数组,保持数据排序的成本为 O(nlogn)。对于已排序的容器,成本按 n 插入分摊;使用数组,当您致电sort()时,您可以立即全部付款。

    如果您根本不想对事物进行排序,您可以随时使用linear search,但是如果你经常使用它,你会付钱,因为它是 O(n)算法。

答案 2 :(得分:1)

将您的数据项放入树中,例如AVL树,red-black tree或B + / B-树。然后,您可以搜索有序值。

答案 3 :(得分:1)

对数字进行排序,然后对每个键执行二进制搜索以平分该组。然后,您可以找到丢失密钥两侧的数字。

答案 4 :(得分:1)

将集合转换为列表并对其进行排序,然后对不在集合中的数字运行二进制搜索。结果将是插入点,即如果在那里存在数字的位置。如果您调用n,则排序列表的索引n处的元素是下一个最小的数字,排序列表的索引n+1处的元素是下一个最大的数字。 / p>

您也可以通过在构建时按照排序顺序保存集合来执行此操作,然后搜索插入点变得很容易。这种方法可用于例如Java TreeMap的{​​{3}}和floorEntry()方法。

答案 5 :(得分:1)

将您的集合保存为已排序的列表/数组并执行二分搜索:例如,在Python中,排序列表和标准Python库中的bisect模块符合您对hilt的需求。

答案 6 :(得分:0)

如果获取数组中的键,则可以对数组进行排序,并找到小于所需元素的最后一个元素的索引。然后你就知道你想要的点之前的键的索引,之后的下一个元素就是你之后的那个。

这应该足以让你进行插值。

(使用的数据结构不一定是一个数组,任何可以排序的东西都是正常的。如其他人所建议的那样,平衡的二叉树将是理想的,特别是如果你打算稍后重用数据的话。)

答案 7 :(得分:0)

在未排序的集合中查找第n个元素是O(n)。 (Select Algorithm)虽然在这里你可以把它归结为一个更简单,更不通用的算法,如果你总是想要最小的&下一个最小元素。但一般来说,在未排序列表中找到最小,第二小等元素是O(n)。 (你应该在算法课上教过这个......)

对集合进行排序,然后将元素编入索引为O(n log n)

在有序集合中查找元素是O(log n)(二进制搜索)

答案 8 :(得分:0)

如果您知道每周总会有一个数据点,那么请保持您的HashMap不变并按照您的建议行事......这将是一个恒定的时间操作,因为您将做14个哈希表查找(在搜索日期的每一侧探测7天),每个都进行 O(1)原始操作。

如果你不知道你的数据有多密集,你可以把它保存在RAM中,然后按照许多其他人的建议把它放到一个平衡的树结构中。但是如果您有很多日期并且必须通过网络从数据库加载数据,这可能会很昂贵。