我有一个大数组说..数组[7000]。每个索引都有一个介于0和9之间的数字。然后给出两个索引说x = 100,y = 105我需要找到之间不同元素的数量给定的范围。 假设
array[100]=1;
array[101]=2;
array[102]=1;
array[103]=4;
array[104]=7;
array[105]=2;
现在这里不同元素的数量是4 {即数字1,2,1,7}。 这可以通过在两个索引之间迭代并跟踪数字来计算。但是我面临的主要问题是程序必须执行的查询数量非常大,即操作必须完成几千个x和y的值(比如10 ^ 6个查询),在这种情况下,这个方法会变得安静无效。可能是一个更好的算法,我试着在很多地方搜索它。
答案 0 :(得分:5)
好的,这个解决方案不是内存效率,但它可以用来计算O(1)中的查询。
形成另一个7000x10的2D数组,其中每一行都是该条目的[0到9s]的计数。
因此,无论何时获得查询,您只需要减去行的相应索引以获得[0..9]数字的计数。
检查哪些指数具有非零计数差异。
例如,数组行可能如下所示:
A[36] = { 5, 4, 2, 1, 4, 3, 7, 8, 2, 1 }
A[38] = { 6, 4, 2, 1, 4, 3, 7, 8, 2, 2 }
Diff = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
因此在36和38之间有两个独特的元素(0和9)。
例2:
对于输入数组{1,2,3,2,4},矩阵A应为:
A[0] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }
A[1] = { 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 }
A[2] = { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0 }
A[3] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0 }
A[4] = { 0, 1, 2, 1, 1, 0, 0, 0, 0, 0 }
因此对于A [3]到A [4],应该有1个唯一元素(4)
Diff = { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }
因此对于A [1]到A [4],应该有3个唯一元素(2,3,4)
Diff = { 0, 0, 1, 1, 1, 0, 0, 0, 0, 0 }
编辑:我已经考虑过A [1]到A [4]的含义是指数[2到4]中的唯一元素。如果需要,可以将其更改为1到4。在那种情况下,
Diff = { 0, 0, 2, 1, 1, 0, 0, 0, 0, 0 }
(同样有3个独特元素)
答案 1 :(得分:2)
您正在寻找分段树。
http://en.wikipedia.org/wiki/Segment_tree
从每个索引的值介于0-1之间的问题开始,然后逐步提升。您可以使用O(logn)时间回答查询,并使用O(nlogn)时间构建树。
答案 2 :(得分:2)
由于你的瓶颈是查询时间,而数组元素是0-9,这是我的解决方案,只有O(n)。
Assume:
A = arr
P = {} (Hash or Dict)
P[A,0,-1] = [0,0,0,0,0,0,0,0,0,0]
For i = 0,len(A):
e = A[i]
P[A,0,i] = P[A,0,i-1] where P[A,0,i-1][e]++
Query(A,x,y)
res = 0
ax = P[A,0,x]
ay = P[A,0,y]
for i = 0,10
res += ay[i] - ax[i] > 1 ? 1 : ay[i] - ax[i]
return res + 1
A = [1,2,1,4,7,2,2]
P [A,0,0] = [0,1,0,0,0,0,0,0,0,0]
P [A,0,1] = [0,1,1,0,0,0,0,0,0,0]
P [A,0,2] = [0,2,1,0,0,0,0,0,0,0]
P [A,0,3] = [0,2,1,0,1,0,0,0,0,0]
P [A,0,4] = [0,2,1,0,1,0,0,1,0,0]
P [A,0,5] = [0,2,2,0,1,0,0,1,0,0]
P [A,0,6] = [0,2,3,0,0,0,0,0,0,0]
查询(A,1,4)= [0,1,0,1,0,0,0,0,1,0,0] = 3 + 1 = 4
查询(A,4,6)= [0,0,2,0,0,0,0,0,0,0,0] = [0,0,1,0,0,0,0 ,0,0,0,0] = 1 + 1 = 2
答案 3 :(得分:1)
由于数字在0-9范围内,我们可以使用一些不错的作弊。
主要思想:在整数中使用位i
来表示存在数字i
。所以{}变为0,{0}变为1,{1}变为2,{0,1}变为3,依此类推。向x
添加项set | (1 << x)
很容易,只需要set1 | set2
,类似地,两个这样的集合的联合是微不足道的:(1 << array[i]) | (1 << array[i + 1])
。还有一种很好的方法来计算整数中1位的数量,这给出了集合的基数。
这无济于事,它只是改善了查询的真实性能。但这不是全部。
现在构建一个二叉树,在叶子处以x .. y
为节点。在上面的级别,你采取两个孩子的联合(如果一个孩子不在场,只需要考虑另一个孩子的价值)。这棵树是一个完整的二叉树,所以你应该像binary heap那样存储它(当然它不是堆),以避免在子指针上浪费大量空间。这样,您只需要在不超过输入的数组中存储表示集合的整数。构建此树显然需要O(n)时间。
对于范围1 << array[something]
的查询,取该范围内所有内容的并集*(注意边缘情况),然后计算最终集合的population count(可以稍微优化一下)因为只能设置10位)。这是一个O(log(y - x))操作。
*:要稍微扩展一下,想法是递归树,并且只要范围完全包含当前节点,就返回该节点。如果叶子未完全包含在范围内,请取
{{1}}(来自输入数组)。