Arrays 查找重复超过n/2次的元素

Arrays 查找重复超过n/2次的元素,arrays,algorithm,Arrays,Algorithm,存在一个数组(大小为N),其中一个元素重复了N/2次以上,数组中的其余元素也可以重复,但只有一个元素重复了N/2次以上。找到号码 我可以想出几种方法: 简单地说,将每个数字的计数保存在哈希映射中 最简单的方法是对数组进行排序,第n/2+1个索引处的数字是 所需号码 仅保留找到的连续重复值的计数。检查 分别用于交替存储值的模式 如果想不出更好的解决方案,就必须有一个解决方案 如果一个元素重复超过N/2次,那么它必须是中位数。有很多方法可以让您高效地找到它。无需排序。您可以简单地使用中值选择算法

存在一个数组(大小为N),其中一个元素重复了N/2次以上,数组中的其余元素也可以重复,但只有一个元素重复了N/2次以上。找到号码

我可以想出几种方法:

  • 简单地说,将每个数字的计数保存在哈希映射中
  • 最简单的方法是对数组进行排序,第n/2+1个索引处的数字是 所需号码
  • 仅保留找到的连续重复值的计数。检查 分别用于交替存储值的模式

如果想不出更好的解决方案,就必须有一个解决方案

如果一个元素重复超过N/2次,那么它必须是中位数。有很多方法可以让您高效地找到它。

无需排序。您可以简单地使用中值选择算法来确定第n/2个元素。Quickselect在O(n)预期时间内运行。中位数以O(n)为单位运行。

您熟悉快速排序吗?它有一个名为“partition”的函数,在给定一个值的情况下,该函数将数组划分为一个部分,其中所有大于该值的值(轴)都位于一侧,而所有小于该值的值都位于另一侧。请注意,这不是一种排序,只是一种分离。N/2计数项目将位于两个部分中较大的部分。您可以递归地应用此技术以在O(n)时间内找到元素


wikipedia:quicksort,或基于分区的通用选择算法在第二种方法中,基本上是选择中间元素。请看一看查找数字列表中位数的算法。特别是,a可以很好地处理这个问题,并用O(n)计算它

Hoare的选择算法的工作原理与quick sort非常相似,不同的是它没有递归两个分区,而是只递归一个分区(包含第k个元素的分区)

在C++中,标准库提供了一种选择算法,保证了O(n)平均复杂度。你可以用这个来找到中位数

int a[8] = {5, 1, 1, 1, 2, 1, 3, 1};
int median = *std::nth_element(a, a + 4, a + 8);

请注意,
std::nth_元素
也会对数组进行局部排序。

有一个很好的算法可以解决这个问题,它只使用恒定的外部空间(O(1))在两个过程中工作(总时间O(N))。我有这个算法的一个实现,以及包括正确性证明在内的注释,

这个算法背后的直觉其实很美。假设有一屋子人,每个人都持有数组的一个元素。每当两个人发现对方都没有持有相同的数组元素时,他们两人都会坐下来。最后,在最后,如果有人站着,他们有可能占多数,你可以检查一下这个元素。只要一个元素出现的频率至少为N/2,您就可以保证这种方法将始终找到多数元素

要真正实现该算法,您需要对阵列进行线性扫描,并跟踪当前猜测的多数元素是什么,以及您迄今为止看到它的次数。最初,该猜测未定义,重复次数为零。在遍历数组时,如果当前元素与您的猜测相符,则递增计数器。如果当前元素与您的猜测不匹配,则减少计数器。如果计数器曾达到零,则将其重置为遇到的下一个元素。您可以将此实现视为上述“站在房间里”算法的具体实现。每当两个人遇到不同的元素,他们就会取消(放下计数器)。只要两个人有相同的元素,他们就不会相互影响


为一个完整的正确性证明,引用原始文献(博耶Boyer Moore和Boyer Moore著名的字符串匹配算法),以及C++中的一个实现,检查上面的链接。

< P>这是大多数元素问题。 对于这个问题,有一个单通道、常数空间算法。 下面是一个用python编写的简短算法:


    import random

    items = [1, 2, 3, 4, 5, 5, 5, 5, 5 ]
    # shuffle the items
    random.shuffle(items)

    print("shuffled items: ", items)

    majority_elem = items[0]
    count = 1
    for i in range(1,len(items)):
        if items[i] == majority_elem:
            count += 1
        else: 
            count -= 1
            if count == 0:
                majority_elem = items[i]
                count = 1

    print("majority element : %d" % majority_elem )

  
我们使用可变多数元素来跟踪多数元素和计数器(计数)

  • 最初,我们将数组的第一个元素设置为多数元素

  • 我们在阵列中导航

  • 如果当前元素==多数元素:增量计数

  • else:{递减计数。如果计数为零,则设置计数=1,并设置多数元素=当前元素。}

这个问题有一个变体,不是数组,而是一个非常大的序列,我们不知道前面的长度。在这种情况下,排序或分区是没有帮助的

参考资料:

  • 计算机编程艺术,分册0:组合算法和布尔函数介绍,第0卷;第四卷

使用任何排序算法对数组进行排序。重复时间超过一半的元素将始终是中间元素。复杂性将为nlog(n)

来自维基:通过将所有观察值从最低值排列到最高值,然后选择中间值,可以找到有限数字列表的中位数。基本上排序并给出你的号码:)你不能跑得比O(N)快。排序太过分了。对不起,是指快速选择。修正了输入错误。你博客上有趣的代码部分很好,另一个很好的解释+1。有人能帮我理解当计数器归零时重置计数器是什么意思吗。这一步有什么用?如果我们不这样做会发生什么?非常优雅的实现+1不,这不是多数元素问题。当数组包含2个或2个以上的数字时,此算法失败,重复n/k次。哦,对不起,in没有正确地查看它。如果没有多数怎么办?返回最后一个元素我很高兴