Performance 如何在多个计数器上更快地运行更新?

Performance 如何在多个计数器上更快地运行更新?,performance,data-structures,time-complexity,Performance,Data Structures,Time Complexity,我有一个计数器变量数组(全部初始化为0)。我有k条指令需要在阵列上运行。指令包括递增开始索引和结束索引(包括两者)之间数组的所有值。 例如: n = 5, k = 2 arr = [0,0,0,0,0] 0,2 - (arr = [1,1,1,0,0]) 0,1 - (arr = [2,2,1,0,0]) 最后,我需要将其按计数值的降序排序,这很容易。 我在编写代码以低于O(n^2)的时间复杂度来完成这项工作时遇到了问题。我必须使用两个循环。 Array counts = [0,0,0,0..

我有一个计数器变量数组(全部初始化为0)。我有k条指令需要在阵列上运行。指令包括递增开始索引和结束索引(包括两者)之间数组的所有值。
例如:

n = 5, k = 2
arr = [0,0,0,0,0]
0,2 - (arr = [1,1,1,0,0])
0,1 - (arr = [2,2,1,0,0])
最后,我需要将其按计数值的降序排序,这很容易。
我在编写代码以低于O(n^2)的时间复杂度来完成这项工作时遇到了问题。我必须使用两个循环。

Array counts = [0,0,0,0... n times]
for(Instruction instruction:instructions){
    int start = instruction.start;
    int end = instruction.end;
    for(i=start;i<=end;i++){
        counts.set(i,counts.get(i)+1);
    }
}
数组计数=[0,0,0,0…n次]
用于(说明:说明){
int start=instruction.start;
int end=指令.end;

对于(i=start;i这不是一个解决方案,很抱歉,但可能会有所帮助

不要计算它们,而是按
end
顺序排列
指令
,然后当您需要一个给定的数字
x
时,使用二进制搜索来查找
x
(如果您使用的是java,则有
Array.binarySearch
可以执行此操作,如果找不到搜索的数字,则插入点),然后向后计数元素,直到
end==x
,然后继续计数,直到
x>=start

// instructions sorted by end
// need to find the "occurrence of x"
int occurence = 0;
int pos = instructions.binarySearch();
int i = pos;
while(instructions[i].end == x){
   count++ ;
   i++;
}
i = pos;
while(instructions[i].start <= x){
   if( x <= instructions[i].end)
       count++;
   i++;
}
// count now has the number of occurrence  of x (number of range [start, end] that contains x)
//按结尾排序的指令
//需要找到“x的出现”
int发生率=0;
int pos=instructions.binarySearch();
int i=pos;
while(指令[i].end==x){
计数++;
i++;
}
i=位置;

while(instructions[i].start设
n
为计数器数组的长度。我们可以将计数器视为一系列
n
符号;如果
n=5
,则

. . . . .
我们可以将每条指令
(开始、结束)
解释为在某些元素周围加括号的指令。例如

  • (0,2)=>(…)…
  • (0,1)=>((..)..
  • 以此类推。您的问题是计算括号树中每个元素的深度

    这里有一种方法,用
    -1
    表示
    by
    +1
    ,并取累计和(在Python中)

    如果提供恒定时间数组访问,则这是
    O(N+M)
    ,其中
    N
    是指令数,
    M
    是计数器大小


    顺便说一句,排序也可以使用基数排序或计数排序在线性时间内完成,因为您使用的是整数。

    首先,将其转换为不同的形式。具体来说,将原始的“从开始到结束递增每个项”转换为“从开始到结束向每个项添加V”通过找到原始图像中的重叠区域并将其组合

    例如,“将1添加到项目1至5,然后将1添加到项目3至8”将变为“将1添加到项目1至2,然后将2添加到项目3至5,然后将1添加到项目6至8”

    这意味着数组中的每个元素只被触摸一次(并且从不多次递增)

    第二,通过引入“从头到尾为项目添加零”(以便数组中的每个项目都包含在一个范围内),您可能可以获得一点排序速度,对每个范围中的项目进行排序,然后合并最终的预排序范围。我的想法是,通过按添加值的顺序合并范围,并跟踪“迄今为止的最高值”,有时您会发现添加到范围中的值大于“迄今为止的最高值”您可以简单地连接/复制而不是合并(并避免“如果value1小于value2”分支)

    当然,如果您在执行任何操作之前就知道项目已排序,或者在执行任何操作之前就知道数组已归零,那么这将明显更好,因为这样可以避免在合并之前对每个范围进行排序


    注意:如果数组总是预先初始化为零(而不仅仅是初始化为零一次,然后定期更新);那么“加法”变成“设置”;将不进行排序(因为一个范围内的所有值都是相同的)也就是说,您可以生成一个全新的数组(而不用预先将数组初始化为零).

    指令是按某个东西排序的吗?目前是随机的。如果它能让一切变得更快,可以根据您的方便进行排序。您的解决方案与@hilberts\u酗酒问题共享的解决方案非常相似。但他/她对此有更直观的方法。@GokuAfrica:我的解决方案最初是为“数组初始化为零一次,然后在该情况下(在执行一组“指令”之前,数组包含非零值)持续/定期更新,然后针对“数组总是事先归零”的情况进行修改。之后所做的修改类似于hilberts_问题的解决方案。
    import numpy as np
    
    # counter array with 5 elements
    ctr = np.zeros(5+1)
    instructions = [(0, 2), (0, 1)]
    for s, e in instructions:
      ctr[s] += 1
      ctr[e+1] -= 1
    
    result = ctr.cumsum()[:5]
    print(result)
    # [2. 2. 1. 0. 0.]