【问题标题】:Constant time binning of values值的恒定时间分箱
【发布时间】:2025-11-21 14:10:01
【问题描述】:

假设我有一个值向量,代表类的上边界,以对(bin)值进行分类。例如向量 { 1, 3, 5, 10 } 表示 bin [0, 1[, [1, 3[, [3, 5[ 和 [5,10[。如何在恒定时间内实现这些类(0,1,2,3)之一中的随机值 V 的分类?遍历边界列表并在 V 超过 bin 的上边界时停止是微不足道的;但这是 O(n) wrt 箱的数量;我希望在恒定时间内做到这一点。

在我真正输入代码之前,我认为这是微不足道的,通过设置一个查找表,根据类边界将每个 V 除以某个值,然后使用除法的(四舍五入)结果来查找 bin查找表中的编号。但是我发现它比我想象的要困难得多,以一种通用的方式来最小化查找表的大小,同时仍然是准确的,而不管 bin 边界之间的比例距离如何;并且以一种适用于所有真实价值的方式。使用 Google'ing,我只能找到确定垃圾箱边界的算法,至少使用我所做的术语。

【问题讨论】:

  • 如果这真的是关于随机抽样的问题,请在谷歌中搜索别名方法。
  • 我刚刚了解到反转方括号也表示排除元素。看看他们是否像那样挨在一起是非常痛苦的(与[0, 1)相比,这意味着相同)。

标签: algorithm classification


【解决方案1】:

我怀疑有没有一种方法可以在严格恒定的时间内(并且不需要无限的空间)而不利用给定数字的某些属性。


查找表是一个不错的主意,但浮点值使这变得困难。如果位数是有限的,您可以考虑将查找表本质上表示为trie(每个级别代表一个数字的树)。

所以对于{1, 2.5, 5, 9},你的树看起来像这样:

                              root
  /   /          /          /  |  \   \   \   \   \
 0   1          2          3   4   5   6   7   8   9
          /     |     \
       2.0 ... 2.5 ... 2.9

每个叶节点都会包含一个值,指示它属于哪个区间,所以
0 将被设置为 0,
1, 2.0 - 2.4 都将设置为 1,
2.5 - 2.9, 3 - 4 将设置为 2,
5 - 9 将设置为 3

一个查询将只涉及从根开始并重复到与我们正在查找的数字中的下一个数字相对应的子节点(如果您在上面的树中查找 2.65,您首先转到 2,然后2.6,那么,既然是叶子,就停下来,返回它的值,即1)。

查询的时间复杂度为O(d),其中d 是向量中的有效位数,空间复杂度为O(nd)

这听起来可能不是特别有效,但请记住,d数字 的数量 - 例如,这将是 d = log mm 是最大可能值,如果我们说的是正整数。


如果您只是设置 binary search tree (BST),其中包含映射到其原始索引的向量中的所有值,

O(log n) 相当简单。

查找看起来与您搜索 BST 的方式非常相似 - 从根开始,然后向左或向右移动,直到找到值,除了在这种情况下,您记下您访问的每个节点并返回映射的索引不是更大的最接近的值。一些 API 的方法基本上可以为您执行此操作(例如 C++ 中的 std::map)。

【讨论】:

    【解决方案2】:

    我认为获得 O(1) 的唯一方法是创建一个查找表,以便您可以直接查找所有值。

    这只有在边界表现良好时才可行:

    1. 预期数字是整数或边界是整数或精度有限。这允许您在检查查找表之前对数字进行四舍五入(取整),并大大减少表所需的条目。

    2. 最大和最小边界之间的差异不能太大。假设我们知道边界的精度为 0.5,最小值为 1,最大值为 10,那么查找表需要 (10-1)/0.5 = 18 个条目。

    第一组和最后一组(小于最小值和大于最大值)的检查是通过简单的 if 检查完成的,不会影响复杂性。

    【讨论】: