【问题标题】:Query on a array查询数组
【发布时间】:2015-12-12 17:22:04
【问题描述】:

假设我有一个数组 A = {a, b, c, d, e, f, g, h........} 和 Q 查询。在每个查询中,我都会被要求执行以下操作之一:

  1. 1 i j -> i 元素加 1, j 元素减 1
  2. 2 x -> 告诉数组中小于x的元素个数

如果没有更新操作,我可以通过下限做到这一点。我仍然可以通过对数组进行排序并找到下限来做到这一点,但复杂性会太高,因为数组 A 和 Q 的大小都可以是 10^5。有没有更快的算法或方法来做到这一点?

【问题讨论】:

  • 这是一个 C++ 问题吗?
  • 对不起,我标记错了

标签: arrays algorithm adhoc


【解决方案1】:

最简单的方法是使用 std::count_if。

您必须满足什么复杂性限制? 10^5^2 仍然只有 10^10。

如果你必须做得比这更好,我怀疑你必须有一个“值”,它有一个指向“索引”的反向指针,以及一个“索引”,它是一个指向值的指针。最初对值进行排序,然后在更新时将值移动到正确的位置。 (可能最好在搜索之前查看该值是否需要移动)。

那么查询还是下界操作。

【讨论】:

    【解决方案2】:

    一旦对数组进行排序(O(n log n) 复杂度),查询“LESS(X)”将在log n 时间内运行,因为您可以使用二进制搜索。一旦您知道在位置 k-th 找到元素 X(或找到 A 中的下一个最大元素),您就知道 k 是您的答案(k 个元素小于 X)。

    (i, j) 命令意味着数组在紧邻min(A[i]+1, A[j]-1) 的元素和紧随max(A[i], A[j]) 之后的元素之间进行部分重新排序。您可以在 log n、最坏情况 log n + n、时间中找到这些:这接近最坏情况:

    k    0  1  2  3  4  5  6  7  8  9           command: (4, 5)
    v    7  14 14 15 15 15 16 16 16 18
                     ^  ^
           becomes 16    becomes 14 -- does it go before 3 or before 1?
    

    然后重新排序是最坏的情况 n,因为 除了两个元素之外,您的数组几乎已经排序,这意味着使用两次 insertion sort 运行会做得很好。 p>

    因此,使用 m 个更新查询和 q 个简单查询,您可以期望拥有

    n log n + m*2*(log n + 2*n) + q * log n
    

    复杂性。平均情况(无病态数组,合理稀疏,无病态更新,(j-i) = d

    ( n + 2m + q ) * log n + 2m*d
    

    这是线性的。在 n = m = q = 10^5 的情况下,您得到的总体复杂度仍低于 10^7,除非您有病态数组和临时查询,在这种情况下,复杂度应该是二次的(甚至可能是三次的;我没有仔细检查过)。

    在现实世界的场景中,您还可以想象使用一些技巧。记住 i 和 j 的修改索引的最后一个值,以及最后一个位置查询 k。这花费很少。现在在下一个查询中,您很有可能可以使用这三个值之一来启动您的二分搜索并节省一些时间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-11
      • 2017-04-30
      • 2018-12-20
      • 2019-07-02
      • 2016-06-17
      • 2016-12-28
      • 2022-01-10
      相关资源
      最近更新 更多