我有一个数组,用整数填充。我的工作是快速找到阵列任何部分的多数元素,我需要这样做...... 记录时间,而不是线性,但事先我可能需要一些时间来准备阵列。
例如:
1 5 2 7 7 7 8 4 6
查询:
[4, 7]
返回7
[4, 8]
返回7
[1, 2]
返回0
(没有多数元素),依此类推......
我需要为每个查询找到答案,如果可能的话,它需要快速执行。
为了准备,我可以使用 O(n log n)时间
答案 0 :(得分:9)
技巧
在查找多数元素时,您可以丢弃没有多数元素的区间。见Find the majority element in array。这使您可以非常简单地解决这个问题。
<强>制备强>
在准备时,递归地将数组分成两半并将这些数组间隔存储在二叉树中。对于每个节点,计算数组间隔中每个元素的出现次数。您需要一个提供O(1)插入和读取的数据结构。我建议使用unsorted_multiset,它平均按需要运行(但最坏情况插入是线性的)。还要检查间隔是否具有多数元素,如果存在则存储它。
<强>运行时强>
在运行时,当要求计算范围的多数元素时,请深入到树中以计算完全覆盖给定范围的间隔集。使用这个技巧来组合这些间隔。
如果我们有多数元素7 5 5 7 7 7
的数组间隔7
,我们可以拆分并丢弃5 5 7 7
,因为它没有多数元素。实际上五个人已经吞并了两个七人组。剩下的是数组7 7
或2x7
。拨打此号码2
多数元素7
的多数点:
数组间隔的多数元素的多数计数是 多数元素的出现次数减去组合出现次数 所有其他元素。
使用以下规则组合间隔以查找潜在的多数元素:
- 丢弃没有多数元素的间隔
- 使用相同的多数元素组合两个数组很简单,只需将元素的大多数计算加起来。
2x7
和3x7
成为5x7
- 当两个阵列组合使用不同的多数元素时,较高的多数计数会获胜。从较高的数字中减去较低的多数计数,以找到最终的多数计数。
3x7
和2x3
成为1x7
。- 如果他们的多数元素不同但具有相同的多数计数,则忽略两个数组。
3x7
和3x5
互相取消。
当所有间隔都被丢弃或组合时,你要么没有任何东西,在这种情况下没有多数元素。或者您有一个包含潜在多数元素的组合区间。查找并在所有数组间隔(也包括先前丢弃的数据间隔)中添加此元素的出现次数,以检查它是否确实是多数元素。
示例强>
对于数组1,1,1,2,2,3,3,2,2,2,3,2,2
,您将得到树(括号中列出多数计数x多数元素)
1,1,1,2,2,3,3,2,2,2,3,2,2
(1x2)
/ \
1,1,1,2,2,3,3 2,2,2,3,2,2
(4x2)
/ \ / \
1,1,1,2 2,3,3 2,2,2 3,2,2
(2x1) (1x3) (3x2) (1x2)
/ \ / \ / \ / \
1,1 1,2 2,3 3 2,2 2 3,2 2
(1x1) (1x3) (2x2) (1x2) (1x2)
/ \ / \ / \ / \ / \
1 1 1 2 2 3 2 2 3 2
(1x1) (1x1)(1x1)(1x2)(1x2)(1x3) (1x2)(1x2) (1x3) (1x2)
范围[5,10](1索引)由一组间隔2,3,3(1x3),2,2,2(3x2)覆盖。他们有不同的多数元素。减去他们的多数计数,你剩下2x2。所以2是潜在的多数元素。查找并总结数组中实际出现次数2:1 + 3 = 4中的4次.2是多数元素。
范围[1,10]由区间1,1,1,2,2,3,3(无多数元素)和2,2,2(3x2)组成。忽略第一个区间,因为它没有多数元素,所以2是潜在的多数元素。在所有区间中对出现次数2求和:2 + 3 = 10中的5个。没有多数元素。
答案 1 :(得分:3)
实际上,它可以在恒定时间和线性空间(!)
中完成请参阅https://cs.stackexchange.com/questions/16671/range-majority-queries-most-freqent-element-in-range和S. Durocher, M. He, I Munro, P.K. Nicholson, M. Skala, Range majority in constant time and linear space, Information and Computation 222 (2013) 169–179, Elsevier.
他们的准备时间是O(n log n),所需空间是O(n),查询是O(1)。这是一篇理论论文,我并不是要求理解所有这些,但它似乎远非不可能实现。他们正在使用wavelet trees。
有关小波树的实现,请参阅https://github.com/fclaude/libcds
答案 2 :(得分:0)
如果你有无限的记忆,你可以和有限的数据范围(如短的int)在 O(N)时间中做到这一点。
总共O(1)+ O(N)操作。
如果使用地图而不是数组X,也可以使用O(N)内存限制自己。 但是你需要在第1阶段的每次迭代中找到元素。因此你总共需要O(N * log(N))时间。
答案 3 :(得分:-1)
您可以使用MAX堆,数字频率作为保持最大堆属性的决定因素, 我的意思是,例如用于跟随输入数组
1 5 2 7 7 7 8 4 6 5
Heap would have all distinct elements with their frequency associated with them
Element = 1 Frequency = 1,
Element = 5 Frequency = 2,
Element = 2 Frequency = 1,
Element = 7 Frequency = 3,
Element = 8 Frequency = 1,
Element = 4 Frequency = 1,
Element = 6 Frequency = 1
作为MAX堆,频率为3的Element 7将处于根级别, 只检查输入范围是否包含此元素,如果是,那么这是答案,如果否,则根据输入范围转到左子树或右子树并执行相同的检查。
创建堆时只需要一次O(N),但一旦创建,搜索就会有效。
答案 4 :(得分:-3)
编辑:抱歉,我正在解决其他问题。
对数组进行排序并构建有序的对列表(value,number_of_occurrences) - 它是O(N log N).
从
1 5 2 7 7 7 8 4 6
它将是
(1,1) (2,1) (4,1) (5,1) (6,1) (7,3) (8,1)
在此数组的顶部,使用对(best_value_or_none
,max_occurrences
)构建二叉树。它看起来像:
(1,1) (2,1) (4,1) (5,1) (6,1) (7,3) (8,1)
\ / \ / \ / |
(0,1) (0,1) (7,3) (8,1)
\ / \ /
(0,1) (7,3)
\ /
(7,3)
这个结构肯定有一个奇特的名字,但我不记得了:)
从这里开始,O(log N)
获取任何间隔的模式。任何间隔都可以分成O(log N)
预先计算的间隔;例如:
[4, 7] = [4, 5] + [6, 7]
f([4,5]) = (0,1)
f([6,7]) = (7,3)
,结果是(7,3)。