出现次数超过一半的数
题意:给定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越大,尝试次数越小。。
个性签名:时间会解决一切