题目:输入n个整数,输出整数中最小的k个元素。
思路:
1.朴素算法,利用random快排,在nlgn时间内得到排序好的数组,然后输出前k个。时间复杂度有点高啊~
2.对想法1进行优化,是否可以先对k个数进行排序,时间复杂度klgk,然后对一个排好序的数组进行二分插入需要lgk的时间,做n-k次,则可以完成,时间复杂度为nlgk
代码如下:
int piviotion(int*a,int p,int q){
int pivot = a[q];
int i=p;
int j=p;
for (;j<q;j++)
{
if (a[j]<pivot)
{
int temp = a[j];
a[j] = a[i];
a[i] = temp;
i++;
}
}
a[q] = a[i];
a[i] = pivot;
return i;
}
void randomQuickSort(int*a,int p,int q){
//randomQuickSort需要随机选择划分index,这里为了简便,偷懒了,选择最后一个元素作为划分。
if (p>=q)
{
return;
}
int r = piviotion(a,p,q);
randomQuickSort(a,p,r-1);
randomQuickSort(a,r+1,q);
}
int getBinaryInsertIndex(int*a,int p,int q,int ele){
if (p<=q)
{
int k = (p+q)/2;
int value = a[k];
if (ele<value)
{
return getBinaryInsertIndex(a,p,k-1,value);
}
else if (ele>value)
{
return getBinaryInsertIndex(a,k+1,q,value);
}else if (ele==value)
{
return k;
}
}
return -1;
}
void binaryInsert(int*a,int p,int q,int ele){
int index = getBinaryInsertIndex(a,p,q,ele);
if (index==-1)
{
return;
}
else{
for (int i=index;i<q;i++)
{
a[i+1] = a[i];
}
a[index]=ele;
}
}
void findMinK(int*a,unsigned int num,unsigned int k){
if (a==NULL)
{
return;
}
if (num==0||k==0)
{
return;
}
int *b = new int[k];
// 将a的前k个元素拷贝进b,并对b进行排序(排序算法为klgk),此步骤共用时间O(k+klgk) = O(klgk)
for (int i=0;i<k;i++)
{
b[i] = a[i];
}
randomQuickSort(b,0,k-1);
//将a中剩下的n-k个元素插入到已经排好序的k个元素中,利用二分插入,此步骤共用时O((n-k)*lgk) = O(n*lgk)
for (int i=k;i<num;i++)
{
binaryInsert(b,0,k-1,a[i]);
}
//打印数组b,用时O(k)
for (int i=0;i<k;i++)
{
cout<<b[i]<<" ";
}
cout<<endl;
//综上所述,时间复杂度为O(n*lgk)
}