保持数组索引的变化

时间:2014-04-28 11:30:19

标签: arrays algorithm data-structures

假设一个数组 arr [1..N] 的整数。数组以两种方式更改:

  • 正在覆盖值
  • 项目被视为无效(例如,通过设置特殊值-1

我正在寻找能够回答" k - 有效项目是什么的数据结构?"快。

使用单个无效值,这是微不足道的。有许多这样的价值观,它变得有点纠结。

我尝试保留一个辅助数组,其中包含无效索引10。我可以保留此数组的前缀和,并在 O(log n)时间查询它们。然后我知道在1和 k 之间存在 sum(k)无效项,因此 k -th项实际上在 k + sum(k)。但是,在 k k + sum(k)之间,可能会再次出现一些无效项 - 而且会变得很丑陋。

这个问题是否有更好的解决方案,可能是在 O(log n)时间?

度过美好的一天!

3 个答案:

答案 0 :(得分:1)

您可以使用包含索引的订单统计信息树(例如,基于RB或其他平衡搜索树)。删除和搜索都需要O(logN)时间

答案 1 :(得分:1)

如果您只在order statistics tree(除了数组)中存储有效索引(实际索引,而不是那些索引处的元素),那么将允许在O中获取第k个项目(记录n)时间。

订单统计树基本上是binary search tree(具体来说是self-balancing one以获得所需的性能),但每个节点存储一个附加值,该值是以该节点为根的子树的大小(即它下面的节点数。)

这同样允许在O(log n)时间内通过简单的BST删除操作进行无效。

覆盖需要O(1)时间 - 不需要对树进行任何更改。


同时拥有数组和顺序统计树并不是必需的 - 您也可以让树节点包含元素,但这会使覆盖取O(log n)而不是O(1)。

答案 2 :(得分:1)

  

我尝试保留一个辅助数组,对于无效索引包含1,否则为0。我可以为这个数组保留前缀和,并在O(log n)时间内查询它们。然后我知道在1和k之间存在和(k)无效项,因此第k项实际上是k + sum(k)。但是,在k和k + sum(k)之间,可能会再次出现一些无效的项目 - 而且会变得很难看。

您可以使用binary-indexed tree来维护前缀和,并快速选择辅助数据结构中的查询:

int tree[N+1] = {0}; // initially everything is invalid
void validate(int i, bool v=1) {  // v = 1: validate, v = 0: invalidate
  for (; i <= N; i += i & -i) 
    tree[i] += v ? 1 : -1;
}
int kth(int k) { // find kth valid index (argument and result 1-based)
  int ans = 0;
  for (int i = logN; i >= 0; --i) // logN = largest i s.t. (1<<i) <= N
    if (ans + (1<<i) <= N && tree[ans + (1<<i)] < k) {
      ans += 1<<i;
      k -= tree[ans];
    }
  return ans+1;
}
// validate everything
for (int i = 1; i <= N; ++i)
  validate(i);

由于较低的常数因子,两个操作都是O(log n)并且比二叉搜索树快得多。这很神奇。