【问题标题】:how to add increasingly more to an array如何向数组中添加越来越多的内容
【发布时间】:2021-12-13 09:37:20
【问题描述】:

有没有办法获得以下类型的 Q 个不同更新:

v[start] = v[start] + 1;
v[start + 1] = v[start + 1] + 2;
v[start + 2] = v[start + 2] + 3

以此类推..到位置结束

v[end] = v[end] + end - start + 1

在 O(N+Q) 中?
我的意思是像差异数组。你能帮帮我吗?
如果有帮助,数组最初只有 0。
澄清:
N = 数组大小
Q = 更新次数
所有更新都有不同的开始和结束索引,我不需要在更新之间访问数组的任何元素。我只在每次更新后才需要它们。

【问题讨论】:

  • 我没有想到任何花哨的东西,但我认为 for 循环可以完成这项工作。
  • 是的。我一直在寻找 O(Q+N) 的解决方案。而 for 循环将是 O(N*Q)
  • Q 是更新次数。
  • 如果初始数组全为 0,那么 std::iota(v + start, v + end, v[start]) 应该可以解决问题。
  • 我很确定您可以跟踪每个索引范围的开始和结束并在之后生成元素,但我无法完全确定细节......我会写用手算出一些这样的总和并寻找模式。

标签: c++ algorithm


【解决方案1】:

糟糕,我将问题理解为

v[start] = v[start] + 1;
v[start + 1] = v[start] + 2;
v[start + 2] = v[start + 1] + 3

这听起来像是 scan 方法的工作(例如与 Haskell 的 scanl 比较),例如std::transform_exclusive_scan:

#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>

int main() {
  std::vector v{0, 0, 0, 0};
  int value_increment = 1;
  std::transform_inclusive_scan(
      v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "),
      std::plus<int>{},
      [&value_increment](int x) { return x + value_increment++; });
  // 1 3 6 10
}

【讨论】:

    【解决方案2】:

    您正在以类似的方式更改范围中的每个成员,因此 std::transform 可以满足您的需求。唯一有点棘手的事情是每次都会增加一个额外的变量。 (示例未编译或测试)

    int i = 0;
    std::transform(std::begin(v), std::end(v), std::begin(v),
                   [&](int e) { return e + (++i); });
    

    【讨论】: