我们有一个原始数组和一个过滤器列表,其中每个过滤器都包含允许通过过滤器的索引。过滤器相当不错,例如它们按以下方式对每个2的幂进行分组(过滤器最多为n = 20)。
1 (2^0) = 1 3 5 7 9 11 13 15 17 19
2 (2^1) = 1 2 5 6 9 10 13 14 17 18
4 (2^2) = 1 2 3 4 9 10 11 12 17 18 19 20
8 (2^3) = 1 2 3 4 5 6 7 8 17 18 19 20
我希望你明白这个主意。现在我们将部分或全部这些过滤器(用户指示要应用哪些过滤器)应用于原始数组,并且转换数组的元素的xor就是答案。举一个例子,如果原始数组是[3 7 8 1 2 9 6 4 11]
,例如n = 9,我们需要应用4,2和1的过滤器,转换将是这样的。
[3 7 8 1 x x x x 11]
[3 7 x x x x x x 11]
[3 x x x x x x x 11]
现在是3和11的xor,例如8是答案。我可以解决这个O(n * no。过滤器)时间,但我需要一个更好的解决方案,它可能在O(没有过滤器)时间给出答案。有没有办法利用xor的属性和/或预先计算一些结果,然后给出过滤器的答案。这是因为有很多带过滤器的查询,所以我需要在O(没有过滤器)时间内回答查询。任何形式的帮助将不胜感激。
答案 0 :(得分:0)
可以在O(M)中完成,其中M是通过以特定方式迭代数组通过所有过滤器的项目数(与过滤器数无关),仅生成通过所有过滤器的索引
如果您从零开始写下示例,则更容易看到:
0 2 4 6 8 10 12 14 16 18
(不包含1的数字)0 1 4 5 8 9 12 13 16 17
(不包含2的数字等)0 1 2 3 8 9 10 11 16 17 18 19
0 1 2 3 4 5 6 7 16 17 18 19
过滤器实际上只是对数组中索引位的约束。该约束的格式为index & filters = 0
,其中filters
只是所有单个过滤器的总和(例如1 + 2 + 4 = 7)。给定有效索引i
,可以仅使用基本操作来计算下一个有效索引i'
:i' = (i | filters) + 1 & ~filters
。这里的想法是将被过滤的位设置为零,这样+1将通过它们,然后再次清除过滤的位以使索引有效。总效果是未经滤波的位递增,滤波后的位保持为零。
这提供了一种简单的算法,可以直接遍历所有有效索引。从0开始(始终有效)并使用上面的规则递增,直到到达数组的末尾:
for (int i = 0; i < N; i = (i | filters) + 1 & ~filters)
// do something with array[i], like XOR them all together