题目:如何在O(N)的时间复杂度内找出数组中出现次数超过了一半的数
例:在数组{1,3,3,3,4}中,3即为所求。
方法1:建立hash表,key为数组不同的元素,value为出现的次数,找出value大于len/2的值即可,时间复杂度为O(n)。
C代码实现:
#include <stdio.h>
#define MAX 2048
void findMostAppear(int a[],int len,int b[])
{
if(a==NULL || len<=0)
return;
int count[MAX]={0};
int i;
int temp=0 ;
for(i=0;i<len;i++)
{
temp=++count[a[i]];
if(temp>len/2) //当求出现次数为一半的元素时,temp==len/2即可
{
b[0]=temp;
b[1]=a[i];
}
}
}
int main()
{
//int a[]={1,3,4,5,6,3,5,6,4,5,6,6,6,7,6,6,7,6};
int a[]={1,3,3,3,4};
int len = sizeof(a)/sizeof(a[0]);
int b[2]={0};
findMostAppear(a,len,b);
printf("%d",b[1]);
return 0;
}
方法2:每次取出两个不同的数字,剩下的数字中重复出现的数字肯定比其他数字多,将规模缩小化。如果每次删除两个不同的数(不管是否包括最高频数),那么在剩下的数字里,原来最高频率的数字出现的频率仍然超过一半······重复该过程,最后剩下的数字将全是同样的数字。时间复杂度为O(n).
C代码实现:
#include <stdio.h>
int FindMostApperse(int a[], int len)
{
if(a==NULL || len<=0)
return -1;
int candidate = 0;
int count = 0;
int i;
for(i=0;i<len;i++)
{
if(count==0)
{
candidate = a[i];
count = 1;
}
else
{
if(candidate == a[i])
count++;
else
count--;
}
}
return candidate;
}
int main()
{
//int a[]={1,3,4,5,6,3,5,6,4,5,6,6,6,7,6,6,7,6};
int a[]={1,3,3,3,4};
int len = sizeof(a)/sizeof(a[0]);
int num = FindMostApperse(a,len);
printf("%d",num);
return 0;
}