• 5.查找最小的k个元素[Kmin]


    【题目】

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

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

    【分析】

    这道题最简单的思路莫过于把输入的n个整数排序,这样排在最前面的k个数就是最小的k个数。只是这种思路的时间复杂度为O(nlogn)。我们试着寻找更快的解决思路。

    我们可以先创建一个大小为k的数据容器来存储最小的k个数字。接下来我们每次从输入的n个整数中读入一个数。如果容器中已有的数字少于k个,则直接把这次读入的整数放入容器之中;如果容器中已有k个数字了,也就是容器已满,此时我们不能再插入新的数字而只能替换已有的数字。我们找出这已有的k个数中最大值,然和拿这次待插入的整数和这个最大值进行比较。如果待插入的值比当前已有的最大值小,则用这个数替换替换当前已有的最大值;如果带插入的值比当前已有的最大值还要大,那么这个数不可能是最小的k个整数之一,因为我们容器内已经有k个数字比它小了,于是我们可以抛弃这个整数。

    因此当容器满了之后,我们要做三件事情:一是在k个整数中找到最大数,二是有可能在这个容器中删除最大数,三是可能要插入一个新的数字,并保证k个整数依然是排序的。如果我们用一个二叉树来实现这个数据容器,那么我们能在O(logk)时间内实现这三步操作。因此对于n个输入数字而言,总的时间效率就是O(nlogk)。

    我们可以选择用不同的二叉树来实现这个数据容器。由于我们每次都需要找到k个整数中的最大数字,我们很容易想到用最大堆。在最大堆中,根结点的值总是大于它的子树中任意结点的值。于是我们每次可以在O(1)得到已有的k个数字中的最大值,但需要O(logk)时间完成删除以及插入操作。

    我们自己从头实现一个最大堆需要一定的代码。我们还可以采用红黑树来实现我们的容器。红黑树通过把结点分为红、黑两种颜色并根据一些规则确保树是平衡的,从而保证在红黑树中查找、删除和插入操作都只需要O(logk)。在STL中set和multiset都是基于红黑树实现的。如果面试官不反对我们用STL中的数据容器,我们就直接拿过来用吧。下面是基于STL中的multiset的参考代码:

    时间复杂度:

    数组存储K个元素:K+(N-K)*(K+1) =O(nk)

    堆存储K个元素:K+(N-K)*(2*lgK+1)=O(nlgk)

    【代码】

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     

    typedef multiset<int, greater<int> >  IntHeap;

    ///////////////////////////////////////////////////////////////////////
    // find k least numbers in a vector
    ///////////////////////////////////////////////////////////////////////
    void FindKLeastNumbers
    (
        
    const vector<int> &data,               // a vector of data
        IntHeap &leastNumbers,                 // k least numbers, output
        unsigned int k
    )
    {
        leastNumbers.clear();

        
    if(k == 0 || data.size() < k)
            
    return;

        vector<
    int>::const_iterator iter = data.begin();
        
    for(; iter != data.end(); ++ iter)
        {
            
    // if less than k numbers was inserted into leastNumbers
            if((leastNumbers.size()) < k)
                leastNumbers.insert(*iter);

            
    // leastNumbers contains k numbers and it's full now
            else
            {
                
    // first number in leastNumbers is the greatest one
                IntHeap::iterator iterMax = leastNumbers.begin();

                
    // if is less than the previous greatest number
                if(*iter < *iterMax)
                {
                    
    // replace the previous greatest number
                    leastNumbers.erase(*iterMax);
                    leastNumbers.insert(*iter);
                }
            }
        }
    }

    【参考】

    http://zhedahht.blog.163.com/blog/static/2541117420072432136859/

    http://blog.csdn.net/liangbopirates/article/details/9377105

    http://blog.csdn.net/v_JULY_v/article/details/6370650

    个人学习笔记,欢迎拍砖!---by hellogiser

    Author: hellogiser
    Warning: 本文版权归作者和博客园共有,欢迎转载,但请保留此段声明,且在文章页面明显位置给出原文连接。Thanks!
    Me: 如果觉得本文对你有帮助的话,那么【推荐】给大家吧,希望今后能够为大家带来更好的技术文章!敬请【关注】
  • 相关阅读:
    suse12安装详解
    Centos7上部署openstack mitaka配置详解(将疑难点都进行划分)
    菜鸟帮你跳过openstack配置过程中的坑[文末新添加福利]
    openstack中dashboard页面RuntimeError: Unable to create a new session key. It is likely that the cache is unavailable.
    Multiple network matches found for name 'selfservice', use an ID to be more specific.报错
    查看 SELinux状态及关闭SELinux
    SELinux深入理解
    IP地址、子网掩码、网络号、主机号、网络地址、主机地址
    Oracle job procedure 存储过程定时任务
    POI文件导出至EXCEL,并弹出下载框
  • 原文地址:https://www.cnblogs.com/hellogiser/p/3738399.html
Copyright © 2020-2023  润新知