• 查找最小的k个元素 【微软面试100题 第五题】


    题目要求:

      输入n个整数,输出其中最小的k个。

      例如:输入1,2,3,4,5,6,7,8这8个数字,则最小的4个数字为1,2,3,4。

    参考资料:剑指offer第30题。

    题目分析:

      解法一:

        用快排的思想,但是最小的k个数不用排序,时间复杂度O(n).

        优点:时间复杂度好,缺点:会修改原整数数组顺序。

      解法二:

        创建一个大小为k的最大堆,遍历一遍数组,同时不断修改最大堆。时间复杂度O(nlogk).

        优点:不会修改原数组,适用于海量数据。缺点:比解法一时间复杂度高。

      其他解法:

        1.快排,取前k个数,时间复杂度O(nlogn).

        2.遍历k次,时间复杂度O(k*n).

        3.位图排序,取前k个数,时间复杂度O(n).会占用额外的空间.

    解法一代码:

    #include <iostream>   
    #include <stdlib.h>    
    using namespace std;   
    
    inline int my_rand(int low, int high)   
    {   
        int size = high - low + 1;   
        return  low + rand() % size;   
    }
    int partition(int a[], int low, int high)   
    {   
        int val = a[low];
    
        while(low<high)
        {
            while( (low<high) && (a[high]>=val) )
                high--;
    
            a[low] = a[high];
            while( (low<high) && (a[low] <= val) )
                low++;
            a[high] = a[low];
        }
        a[low] = val;
        return low;
    }
    void swap(int *a,int i,int j)
    {
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
    bool rand_select(int array[], int left, int right, int k)   
    {   
        //第k 小元素,实际上应该在数组中下标为 k-1   
        if (k-1 > right || k-1 < left)      
            return false ;   
    
        if(left<right)
        {
            //随机从数组中选取枢纽元元素   
            int index = my_rand(left, right);
            swap(array,index,left);
    
            int pos = partition(array , left, right);   
            if(pos == k-1)   
                return true ;   
            else if (pos > k-1)   
                return rand_select(array , left, pos-1, k);   
            else return rand_select(array, pos+1, right, k); 
        }
        else
            return true ; 
    }   
    int main()   
    {   
        int array1[] = {7, 8, 9, 12, 6, 4, 11, 1, 2, 33};      
    
        int numOfArray = sizeof (array1) / sizeof( int);   
        for(int i=0; i<numOfArray; i++)   
            cout << array1[i] << " ";
        cout << endl;
    
        int K = 5;      
        bool flag = rand_select(array1, 0, numOfArray-1, K);     
        
        if(flag)
        {
            cout << "最小的" << K << "个数为:";
            for(int i=0; i<K; i++)   
                cout << array1[i] << " ";
            cout << endl;
        }
        return 0;   
    }  
    View Code

    解法二代码:

    //从头实现一个最大堆需要一定的代码,可以采用c++中的红黑树来实现。
    //其中set和multiset都是基于红黑树实现的,后者可以支持数组中有重复
    #include <iostream>
    #include <set>
    #include <vector>
    
    using namespace std;
    
    typedef multiset<int,greater<int>> intSet;
    typedef multiset<int,greater<int>>::iterator setIterator;
    
    void getLeastNumbers(const vector<int> &data,intSet &leastNumbers,int k);
    
    int main(void)
    {
        int a[8] = {1,2,8,4,5,6,7,3};
        const vector<int> data(a,a+8);//8不是7
    
        intSet leastNumbers;
        int k = 5;
    
        getLeastNumbers(data,leastNumbers,k);
        
        cout << "最小的" << k << "个数为:";
        setIterator iter = leastNumbers.begin();
        for(;iter!=leastNumbers.end();++iter)
            cout << *iter << " ";
        cout << endl;
        return 0;
    }
    void getLeastNumbers(const vector<int> &data,intSet &leastNumbers,int k)
    {
        leastNumbers.clear();
    
        if(k<1 || k>data.size())
            return ;
    
        vector<int>::const_iterator iter = data.begin();
        for(;iter != data.end();++iter)
        {
            if(leastNumbers.size() < k)
                leastNumbers.insert(*iter);
            else
            {
                setIterator iterGreatest = leastNumbers.begin();
                if(*iter < *iterGreatest)
                {
                    leastNumbers.erase(*iterGreatest);
                    leastNumbers.insert(*iter);
                }
            }
        }
    }
    View Code
  • 相关阅读:
    【译】可扩展前端2  —  常见模式
    【译】可扩展前端1  —  架构基础
    【译】The Clean Architecture
    获取页面元素位置
    vue高价组件的使用
    gif动态图片转精灵图
    消除 transition 闪屏
    移动端 -- 如何去掉元素被触摸时产生的半透明灰色遮罩?
    解决手机移动端触屏版web页面长时间按住页面出现闪退的问题
    移动端滑动慢,卡顿
  • 原文地址:https://www.cnblogs.com/tractorman/p/4053558.html
Copyright © 2020-2023  润新知