给定N个数字的数组,找到具有R的范围的所有长度的序列的数量。

时间:2012-10-14 13:51:12

标签: c++ algorithm

这是Given a sequence of N numbers ,extract number of sequences of length K having range less than R?

的后续问题

我基本上需要向量v作为大小为N的答案,使得V [i]表示长度为i的序列的数量,其具有范围<= R。

4 个答案:

答案 0 :(得分:1)

传统上,在递归解决方案中,您将计算K = 0,K = 1的解,然后在后续元素之间找到某种递归关系,以避免每次从头开始重新计算解决方案。

但是在这里我认为,从另一方面攻击问题会很有趣,因为传播的属性:

  

给定一个R(或更少)的扩散序列,任何子序列的扩散都不如R

因此,我首先建立一个从每个索引开始的扩展R的最长子序列的列表。我们将此列表M称为M[i] = j,其中jS(原始序列)S[j] - S[i] <= R中较高的索引。这将是O(N)。

现在,对于任何i,从K开始的长度为i的序列数量为01,这取决于{是否{ {1}}大于K或不大于M[i] - i。对M(从0N-K)的简单线性传递给出了答案。这又是O(N)。

因此,如果我们调用V生成的向量,V[k]表示KS的长度R的子序列数,其差异小于for i in [0, len(M)]: for k in [0, M[i] - i]: ++V[k] ,然后我们可以通过M:

在一次迭代中完成
M[i] - i

算法很简单,但更新次数可能相当艰巨。在最坏的情况下,假设N - i等于{{1}},则为O(N * N)复杂度。您需要一个更好的数据结构(可能是Fenwick树的改编版)来使用这种算法,从而降低计算这些数字的成本。

答案 1 :(得分:0)

如果您正在寻找连续序列,请尝试递归执行:设置范围低于R的K长度子序列包含在(K-1) - 长度子序列集中。

在K = 0时,您有N个解决方案。 每次增加K,你追加(resp.prepend)下一个(resp.previous)元素,检查它是否低于R,并将其存储在一个集合中(查找重复项!)或丢弃它取决于结果。

如果认为在最坏的情况下该算法的复杂度为O(n * n),尽管平均可能更好。

答案 2 :(得分:0)

从一个更简单的问题开始:计算序列的最大长度,从每个索引开始并具有等于R的范围。

为此,让第一个指针指向数组的第一个元素。增加第二个指针(也从数组的第一个元素开始),而指针之间的序列具有范围,小于或等于R.将每个数组元素(由第二个指针传递)推送到min-max-queue,由一对mix-max-stacks,在this answer中描述。当min-max-queue报告的max和min值之间的差异超过R时,停止增加第二个指针,增加V[ptr2-ptr1],增加第一个指针(删除元素,由它指向,从min-max-queue),以及继续增加第二个指针(保持范围受控制)。

当第二个指针离开数组的边界时,对所有剩余的ptr1递增V[N-ptr1](对应的范围可能小于或等于R)。要添加小于R的所有其他范围,请计算从其末尾开始的数组V []的累积和。

时间和空间复杂度都是O(N)。

的伪代码:

p1 = p2 = 0;
do {
  do {
    min_max_queue.push(a[p2]);
    ++p2;
  } while (p2 < N && min_max_queue.range() <= R);

  if (p2 < N) {
    ++v[p2 - p1 - 1];
    min_max_queue.pop();
    ++p1;
  }
} while (p2 < N);

for (i = 1; i <= N-p1; ++i) {
  ++v[i];
}

sum = 0;
for (j = N; j > 0; --j) {
  value = v[j];
  v[j] += sum;
  sum += value;
}

答案 3 :(得分:0)

我认为Matthieu在寻找具有扩散R的所有序列时都有正确的答案。

由于你只是寻找长度为K的序列,你可以做得更好。 不要查看从i开始的最大序列,只需查看从i开始的长度为K的序列,并查看它是否具有范围R.为每个i执行此操作,并且您具有长度为K的所有序列,其中包含R。

您不需要遍历整个列表,因为长度为K的序列的最新起点是n-K + 1。所以复杂性类似于(n-K + 1)* K = n * K-K * K + K.对于K = 1,这是n, 对于K = n,它是n。对于K = n / 2,它是n * n / 2 - n * n / 4 + n / 2 = n * n / 2 + n / 2,我认为这是最大值。因此,虽然这仍然是O(n * n),但对于大多数K值,你会得到更好的效果。