#include<stdio.h>
#include<stdlib.h>
void swap(int* data1,int* data2)
{
int temp=*data1;
*data1=*data2;
*data2=temp;
}
int partition(int data[],int length,int start,int end)//基于Partition函数的O(n)算法
{
if(data==NULL||length<=0||start<0||end>=length)
return 0;
int index=0;
swap(&data[index],&data[end]);
int small=start-1;
for(index=start;index<end;++index)
{
if(data[index]<data[end])
{
++small;
if(small!=index)
swap(&data[index],&data[small]);
}
}
++small;
swap(&data[small],&data[end]);
return small;
}
bool bInputInvalid=false;
bool checkInvalidArray(int* numbers,int length)
{
bInputInvalid=false;
if(numbers==NULL&&length<=0)
bInputInvalid=true;
return bInputInvalid;
}
bool checkMoreThanHalf(int* numbers,int length,int number)
{
int times=0;
for(int i=0;i<length;i++)
{
if(numbers[i]==number)
times++;
}
bool isMoreThanHalf=true;
if(times*2<=length)
{
bInputInvalid=true;
isMoreThanHalf=false;
}
return isMoreThanHalf;
}
/*
int moreThanHalfNum(int* numbers,int length)
{
if(checkInvalidArray(numbers,length))
return 0;
int middle=length>>1;
int start=0;
int end=length-1;
int index=partition(numbers,length,start,end);
while(index!=middle)
{
if(index>middle)
{
end=index-1;
index=partition(numbers,length,start,end);
}
else
{
start=index+1;
index=partition(numbers,length,start,end);
}
}
int result=numbers[middle];
if(!checkMoreThanHalf(numbers,length,result))
result=0;
return result;
}
*/
int moreThanHalfNum(int* numbers,int length)
{
if(checkInvalidArray(numbers,length))
return 0;
int result=numbers[0];
int times=1;
for(int i=1;i<length;i++)
{
if(times==0)
{
result=numbers[i];
times=1;
}
else if(numbers[i]==result)
times++;
else
times--;
}
if(!checkMoreThanHalf(numbers,length,result))
return 0;
return result;
}
int main()
{
int length;
scanf("%d",&length);
int numbers[length];
for(int i=0;i<length;i++)
scanf("%d",&numbers[i]);
printf("%d",moreThanHalfNum(numbers,length));
return 0;
}
题目:
数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字
分析:
看到这道题,我们马上就会想到,要是这个数组是排序的数组就好了。如果是排序的数组,
那么我们只要遍历一次就可以统计出每个数字出现的次数,这样也就能找出符合要求的数字了。
题目给出的数组没有说是排好序的,因此我们需要给它排序。排序的时间复杂度是O(nlogn),
再加上遍历的时间复杂度O(n),因此总的复杂度是O(nlogn)。
接下来我们试着看看能不能想出更快的算法。前面思路的时间主要是花在排序上。
我们可以创建一个哈希表来消除排序的时间。哈希表的键值(Key)为数组中的数字,值(Value)为该数字对应的次数。
有了这个辅助的哈希表之后,我们只需要遍历数组中的每个数字,找到它在哈希表中对应的位置并增加它出现的次数。
这种哈希表的方法在数组的所有数字都在一个比较窄的范围内的时候很有效。
前面两种思路都没有考虑到题目中数组的特性:
数组中有个数字出现的次数超过了数组长度的一半。也就是说,有个数字出现的次数比其他所有数字出现次数的和还要多。
因此我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。当我们遍历到下一个数字的时候,
如果下一个数字和我们之前保存的数字相同,则次数加1。如果下一个数字和我们之前保存的数字不同,则次数减1。
如果次数为零,我们需要保存下一个数字,并把次数设为1。由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,
那么要找的数字肯定是最后一次把次数设为1时对应的数字。
结果: