问题:
现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数。
解析:
这个题目类似于:微软的寻找发帖水王,思想:
类似于擂台赛,设最多的数为X,
每次删除两个不同的数(不管是否为最多的数X),
则我们能保证剩下的数中X还是超过剩余总数的一半,一直循环这个过程,则最后一个肯定是X
简单代码:
int FindMost(const int* A, int N)
{
int Candidata,nTimes = 0,i=0;
while(i < N)
{
if(nTimes==0)
{ Candidata = A[i]; nTimes = 1; }
else
{
if(A[i] != Candidata) --nTimes;
else ++nTimes;
}
++i;
}
return Candidata;
}
简单测试:
const int N = 100;
int A[N],i;
for(i=0; i<N/2+1; ++i) A[i] = 1;
for(; i<N; ++i) A[i] = i+1;
random_shuffle(A, A+N);
cout<<"The Count of Number N more than half of the Array size in:\n";
Print(A, N);
cout<<"\nN = "<<FindMost(A, N)<<endl;
扩展问题:
数组中有3个数字的数目都超过数组的1/4,要求找出这几个数字。
简单代码:
void FindMost_3(const int* A, int N, int* ans)
{
const int INVALID = -1;
int Candidata[3] = {INVALID,INVALID,INVALID},nTimes[3] = {0,0,0},i=0;
while(i < N)
{
if(A[i] == Candidata[0]) ++nTimes[0];
else if(A[i] == Candidata[1]) ++nTimes[1];
else if(A[i] == Candidata[2]) ++nTimes[2];
else if(nTimes[0] == 0) {Candidata[0]=A[i]; nTimes[0]=1;}
else if(nTimes[1] == 0) {Candidata[1]=A[i]; nTimes[1]=1;}
else if(nTimes[2] == 0) {Candidata[2]=A[i]; nTimes[2]=1;}
else {--nTimes[0];--nTimes[1];--nTimes[2];}
++i;
}
ans[0] = Candidata[0];
ans[1] = Candidata[1];
ans[2] = Candidata[2];
}
简单测试:
const int N = 100;
int A[N],i,j,k;
for(i=0; i<N/4+1; ++i) A[i] = 1;
for(j=0; j<N/4+1; ++j) A[i+j] = 2;
for(k=0; k<N/4+1; ++k) A[i+j+k] = 3;
for(k=i+j+k; k<N; ++k) A[k] = k;
random_shuffle(A, A+N);
cout<<"The Count of 3 Number more than 1/4 the Array size in:\n";
Print(A, N);
int X[3];
FindMost_3(A, N, X);
cout<<"\nAnswer 1 = "<<X[0]<<endl;
cout<<"Answer 2 = "<<X[1]<<endl;
cout<<"Answer 3 = "<<X[2]<<endl;