剑指Offer30最小的k个数

来源:互联网 发布:python双击闪退 编辑:程序博客网 时间:2024/06/02 06:19

题目:

输入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;
}


0 0
原创粉丝点击