查询数组中索引范围i,j中的范围A [i],A [j]内的值

时间:2014-09-07 12:24:02

标签: arrays algorithm count

假设我们有一个n个元素的数组(未排序)。给定一个带有两个参数i和j的查询,其中i和j是数组的索引,我想返回值x st的值。 x在范围A[i],A[j](不包括)范围内,x本身在索引范围i<indexof(x)<j内。

例如,数组是[3,6,7,1,2,4,9,1]

i=1 j=7
A[i]=3 A[j]=9

所以从索引1到7的范围3,9内的值是

6,7,4

导致3个值。

我肯定需要做一些预处理,以便我可以在O(logn)时间内回答查询。 我尝试使用Fenwick树来解决这个问题,但我想它需要进行一些修改,而且我不需要对数组进行任何更新,只需回答查询。

编辑:预计算O(n ^ 2)和O(1)查询对我来说不是一个有效选项

2 个答案:

答案 0 :(得分:4)

可以通过使用与合并排序相关的分段树来解决此问题。在对应于范围[l,r]的每个节点处,存储在该节点中的数组将是A [l ... r]的排序数组。我们可以在O(n log n)时间内预处理这个,并且空间复杂度也将是O(n log n),因为每个元素在树的每个高度只出现一次,等于O(log n)。 / p>

构建此树的简单方法是使用O(n log n)算法对每个节点处的数组进行排序,该算法总时间复杂度为O(n log ^ 2 n)。但是我已经提到过这个过程看起来像是合并排序,所以我们可以使用相同的过程来获得O(n log n)构建时间的时间复杂度。

例如,让我们考虑示例数组的前四个元素[3,6,7,1]。我描述的树将如下所示:

    [1,3,6,7]
       /    \ 
  [3,6]     [1,7]
   / \       / \
 [3]  [6]  [7] [1]

现在,如果您在相应节点上二进制搜索元素,则可以在O(log ^ 2 n)时间内完成查询。

建造时间:O(n log n)

查询时间:O(log ^ 2 n)

编辑(用C ++构建树的代码,查询留作练习):

#include <vector>
using namespace std;
const int MAX_N = 10000;

int A[MAX_N], N; // the array of the integers
vector<int> T[MAX_N * 4];

void merge(vector<int>& C, vector<int>& A, vector<int>& B){
  int i = 0, j = 0, n = A.size(), m = B.size();
  C.assign(n + m, 0);
  while(i < n || j < m){
    if(i == n) C[i + j] = B[j], j++;
    else if(j == m) C[i + j] = A[i], i++;
    else {
      if(A[i] <= B[j]) {
        C[i + j] = A[i];
        i++;
      } else {
        C[i + j] = B[j];
        j ++;
      }
    }
  }
}

void build(int n, int L, int R){
  if(L == R) T[n] = vector<int>(1, A[L]);
  else {
    build(n * 2, L, (L + R) / 2);
    build(n * 2 + 1, (L + R) / 2 + 1, R);
    merge(T[n], T[n * 2], T[n * 2 + 1]);
  }
}

int main(){
  N = 4;
  A[0] = 3, A[1] = 6, A[2] = 7, A[3] = 1;
  build(1, 0, N - 1);
  return 0;
}

答案 1 :(得分:0)

这可以通过Fenwick的树来解决。首先让我们假设所有整数都小于10 ^ 6。

阻止您直接使用Fenwick的问题是:如果您在完成Fenwick的树设置后查询,查询(a[i]a[j])将涉及一些要计算a[k]的数字k > j。解决此问题的方法是根据右侧对查询进行排序,并在完成j的Fenwick更新后立即使用正确的索引a[j]完成所有查询。这将确保来自后期索引的数字不会影响以前的计数。

如果所有数字都在整数范围内,请在启动上述例程之前将它们映射到[1..N],其中N是数组的大小。

整体复杂度为O(Q log Q + Q log N),其中Q是查询数量,N是数组的大小。