题目:
输入n个整数,找出其中最小的k个数,例如输入4,5,1,6,2,7,3,8这个8个数字,则最小的4个数字是1,2,3,4.
分析:
最简单的方法就是把它排序,然后找出前面的k个数字就是最小的k个数字,这种思路的时间复杂度是O(nlgn),那么还有没有更快的算法了?
方法1:
我们刚刚解决了29题,出现次数超过一半的数字,那么这个题是不是和他很像,只是这里的这个次数是一个可变的。如果我们运用那个题的思路来想思考的话,就会想到:随机的一个数,它的左边比它小,右边比它大,那么如果这个随机数就是第k个数,那是不是就找到了,并且这种思路的时间复杂度是O(n)的,比刚才的短。
方法2:
我们可以创建一个容量为k的容器,然后遍历数组,每遍历一个数就向容器中存放一个数,当容器中存放了k个数之后那么就开始找出k个数其中最大的那个数和新进来的比较,如果新来的数小就放进容器中,如果大就不放进容器。这样每次遍历容器中的数并进行替换,我们可以把这个容器做成事最大堆,采用红黑树来实现容器,它的查找,删除,和插入操作都是O(logk),所以其整个时间复杂度为O(nlogk)。
两种方法的比较:
方法一是基于Partition其时间复杂度为O(n),比方法二要快,但是方法一是有限制的,它改变了原始数组,如果要求不能改变数组的话,就不适用方法1了。
方法二虽然慢了点,但他是有优点的,1没有改变数组,2,使用于海量数据,如果数据量特别大,那么一次可能不能把所有数据都读入内存,那么这样的话方法一是明显不行的,因它要把所有数据都存如内存才能再做转化和比较,然而方法二就会特别适合,因为他是一个个读数据,并且容器中只存k个数,所以他是适用的。
方法一代码:
int Partation(int *data,int length ,int start,int end)
{
if(data == NULL || length < 0 || start <0 || end >=length)
{
cout<<"出错了"<<endl;
return -1;
}
int index = Random(start,end);
Swap(&data[end],&data[index]);
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;
}
int CheckMoreThanHalf(int *data,int length,int num)
{
int time = 0;
for(int i=0;i<length;i++)
{
if(data[i] == num)
time++;
}
if(time*2<length)
{
cout<<"这个不是"<<endl;
return false;
}
return true;
}
int MoreThanHalfNum(int *data,int length)
{
if(data== NULL || length <0)
{
return 0;
}
int middle = length>>2;
int start =0,end = length-1;
int index = Partation(data,length,start,end);
while(index != middle)
{
if(middle < index)
{
end = index - 1;
index = Partation(data,length,start,end);
}
else
{
start = index + 1;
index = Partation(data,length,start,end);
}
}
int result = data[middle];
if(!CheckMoreThanHalf(data,length,result))
result = 0;
cout<<"找到了!"<<endl;
return result;
}
方法二代码:
int MoreThanHalfNumFangFa2(int *data,int length)
{
if(data == NULL && length < 0)
{
cout<<"数组错误"<<endl;
return -1;
}
int result = data[0];
int time = 1;
for(int i=1;i<length;i++)
{
if(time ==0)
{
result = data[i];
time = 1;
}
else if(data[i] == result)
time++;
else if(data[i] != result)
time --;
}
if(!CheckMoreThanHalf(data,length,result))
result = 0;
cout<<"找到了!"<<endl;
return result;
}