序列的部分产品的节省空间的数据结构?

时间:2015-07-08 09:28:28

标签: algorithm data-structures tree space-complexity

我需要建议一个内存复杂度为O(n)的数据结构,它执行以下操作:

  1. Init() - 初始化一个空数据结构。
  2. Insert (I,x) - 在第i位插入数字x。之前和之后的数字将是一个更高的指数。复杂度:O(logn)
  3. Get(i) - 返回i元素。复杂性:O(logn)
  4. multiplyAllBut(down,up) - 返回乘法数字,而不显示在向下和向上位置之间出现的数字。复杂性:O(logn)
  5. 我考虑过AVL树但是我在更改索引方面遇到了问题。此外,跳过列表,但它不是复杂的。

    感谢。 :)

1 个答案:

答案 0 :(得分:2)

除了最后一个操作(将所有内容乘以一个值)之外,您可以使用order statistic tree实现此操作,这是一个增强的BST,其中每个节点都存储左右两边的元素数。我相信从这个数据结构开始并添加更多信息,您可以使所有四个操作有效地工作。

基本思想如下:扩充树中的每个节点,以存储左子树中所有数字的乘积以及存储在右子树中的所有数字的乘积。我们会将这些称为leftProdrightProd。这些值可以在时间O(1)中根据节点的左右子树中的值和节点本身中的值来计算,因此使用此额外信息扩充树不会改变实现的渐近时间复杂度。此外,还存储两个值:minIndexmaxIndex,以给定节点为根的子树中的最小和最大索引。可以从左右子树中的值有效地计算这两个,因此添加此额外增强不会产生任何成本。

现在,假设您要查找[low,high]范围内值的乘积。为此,请按如下方式递归搜索树:

  1. 如果[low,high]纯粹位于当前节点索引的左侧,则递归计算左子树中的值。
  2. 如果[low,high]纯粹位于当前节点索引的右侧,则递归计算右子树中的值。
  3. 如果[low,high]与范围[minIndex, maxIndex]完全匹配,则返回节点的vaule leftProdrightProd的产品。
  4. 否则,在左子树中为[low,index - 1]进行递归调用,在[index + 1,high]的右子树中进行递归调用,并返回这两个数字的乘积和节点自己的值。
  5. 我们需要证明为什么这会有效地发挥作用。这个想法的关键是以下几点。情况1和2只进行一次递归调用。案例3不进行递归调用。案例4将进行两次递归调用。每个案例都是O(1)。如果不是在案例4中完成分支,则递归将从顶部向下走到树的下方,每个级别执行O(1)工作,因此完成的总工作量为O(log n)。

    但是,我要声称案例4实际上并没有你想象的那么多。想象一下案例4发生时第一次在递归中。如果是这样,它将进行两次递归调用,一次向左,一次向右。请注意,这些递归调用是针对非常特定的子范围的:左子树上的调用请求从左子树中的某个索引到最后一个索引的范围,右子树上的调用请求来自第一个索引的范围。正确的子树到一些索引。换句话说,所做的递归调用是针对它们重复出现的子树的一侧“刷新”的子范围。

    现在,想想从那时起我们遇到案例4的任何时候。每当我们这样做时,我们都知道递归将进入的两个范围之一将包含完整子树的范围。这将立即导致我们击中案例3,因此有效的递归调用不是真正的递归调用。这意味着案例4可以“真正”分支的次数最多一次。从那时起,递归有效地继续沿着树中的一条路径继续。

    总的来说,这意味着我们可以将完成的工作量 - 至少是渐近地 - 限制为从树的顶部向下走到底部两次所需的工作,每个节点执行O(1)工作。根据需要,这可以达到O(log n)的总工作量。

    我们需要多少空间?此扩充每个节点仅使用O(1)空间,因此所需的总空间为O(n)。

    希望这有帮助!