Performance 如何在多个计数器上更快地运行更新?
我有一个计数器变量数组(全部初始化为0)。我有k条指令需要在阵列上运行。指令包括递增开始索引和结束索引(包括两者)之间数组的所有值。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..
例如:
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.]