多数元素 - 数组的一部分

时间:2013-11-03 15:08:14

标签: c++ arrays algorithm c++11 element

我有一个数组,用整数填充。我的工作是快速找到阵列任何部分的多数元素,我需要这样做...... 记录时间,而不是线性,但事先我可能需要一些时间来准备阵列。

例如:

1 5 2 7 7 7 8 4 6

查询:

[4, 7]返回7

[4, 8]返回7

[1, 2]返回0(没有多数元素),依此类推......

我需要为每个查询找到答案,如果可能的话,它需要快速执行。

为了准备,我可以使用 O(n log n)时间

5 个答案:

答案 0 :(得分:9)

技巧

在查找多数元素时,您可以丢弃没有多数元素的区间。见Find the majority element in array。这使您可以非常简单地解决这个问题。

<强>制备

在准备时,递归地将数组分成两半并将这些数组间隔存储在二叉树中。对于每个节点,计算数组间隔中每个元素的出现次数。您需要一个提供O(1)插入和读取的数据结构。我建议使用unsorted_multiset,它平均按需要运行(但最坏情况插入是线性的)。还要检查间隔是否具有多数元素,如果存在则存储它。

<强>运行时

在运行时,当要求计算范围的多数元素时,请深入到树中以计算完全覆盖给定范围的间隔集。使用这个技巧来组合这些间隔。

如果我们有多数元素7 5 5 7 7 7的数组间隔7,我们可以拆分并丢弃5 5 7 7,因为它没有多数元素。实际上五个人已经吞并了两个七人组。剩下的是数组7 72x7。拨打此号码2多数元素7多数点

  

数组间隔的多数元素的多数计数是   多数元素的出现次数减去组合出现次数   所有其他元素。

使用以下规则组合间隔以查找潜在的多数元素:

  
      
  • 丢弃没有多数元素的间隔
  •   
  • 使用相同的多数元素组合两个数组很简单,只需将元素的大多数计算加起来。 2x73x7成为5x7
  •   
  • 当两个阵列组合使用不同的多数元素时,较高的多数计数会获胜。从较高的数字中减去较低的多数计数,以找到最终的多数计数。 3x72x3成为1x7
  •   
  • 如果他们的多数元素不同但具有相同的多数计数,则忽略两个数组。 3x73x5互相取消。
  •   

当所有间隔都被丢弃或组合时,你要么没有任何东西,在这种情况下没有多数元素。或者您有一个包含潜在多数元素的组合区间。查找并在所有数组间隔(也包括先前丢弃的数据间隔)中添加此元素的出现次数,以检查它是否确实是多数元素。

示例

对于数组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-rangeS. 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)时间中做到这一点。

  1. 浏览数组并计算1s,2s,3s,eta的数量(数组中每个值的条目数)。您需要具有sizeof(YouType)元素的其他数组X.
  2. 浏览数组X并找到最大值。
  3. 总共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_nonemax_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)。