出现次数超过一半的数

题意:给定n个整数,有n/2个数相同,另外的n/2个数互异,求出现超过一半的那个数。

分析:

用hashtable的方法可以O(n),但也需要O(n)的额外空间;

采用经典的“多数元素”中的算法,可以O(n),且空间为O(1)。有没有更好的方法呢?

可以采用概率方法,每次取两个数出来比较,直到发现两个相同的数。

#include<cstdio>
#include<cstdlib>

int main()
{
    int a[] = {1, 2, 3, 4, 5, 6, 6, 6, 6, 6};
    int n = 8;
    int i = rand() % n;
    int j = rand() % n;
    while(a[i] != a[j])
    {
        i = rand() % n;
        j = rand() % n;
    }
    printf("%d\n", a[i]);
}

复杂度:

任意两个数不同的概率 $p = \frac{C_n^2 - C_{n/2}^2}{C_n^2} = 1 - \frac{1}{4} \cdot \frac{n-2}{n-1}$

p约等于3/4,p^10= 0.056,也就是说10次还没出结果的概率为0.056,已经比较小了。

有趣的是,n越大,该概率越小。

而尝试次数的期望值X:1*(1-p) + 2*p(1-p) + 3*p^2*(1-p) + 4*p^3*(1-p) + ... = 1/(1-p),啊这,好像能直接看出结果,X*(1-p)=1,X=1/(1-p),所以n越大,尝试次数越小。。

posted @ 2020-07-11 15:03  Rogn  阅读(450)  评论(0编辑  收藏  举报