zoukankan      html  css  js  c++  java
  • 28 最小的K个数

    题目描述

    输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
     
    思路:
    解法1:对于小规模数据,可以采用类似前题的快速排序思路,pivot之前的点都是比它小的,之后的点都是比它大的。不管是找中位数还是找前k大,前k小,都可以使用这个方法,平均复杂度是O(N),但是最坏时间复杂度是O(N*N)。这样得到最后k个数是没有进行排序的,所以降低了时间复杂度。
    这里需要注意idx初值不该设为0,因为找最小的0个数的时候idx = lo = 0;就不会进入循环当中,所以应该注意39行和50行。这题有个大坑就是k的讨论,k可能小于等于0,也可能大于size,所以必须要进行讨论。
    这种方法会对输入的数组进行改变,所以应该要明确告诉面试官这样是否允许。而且这种做法适合小规模数据。
     
     1 class Solution {
     2 public:
     3     int partition(vector<int> &input,int lo,int hi){
     4         int pos = lo + rand() % (hi - lo + 1);
     5         int pivot = input[pos];
     6         swap(input[lo],input[pos]);
     7         while(lo < hi){
     8             while(lo < hi){
     9                 if(input[hi] > pivot){
    10                     --hi;
    11                 }
    12                 else{
    13                     input[lo] = input[hi];
    14                     ++lo;
    15                     break;
    16                 }
    17             }
    18             while(lo < hi){
    19                 if(input[lo] < pivot){
    20                     ++lo;
    21                 }
    22                 else{
    23                     input[hi] = input[lo];
    24                     --hi;
    25                     break;
    26                 }
    27             }
    28         }
    29         input[lo] = pivot;
    30         return lo;
    31     }
    32     vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
    33         if(input.empty() || k > input.size() || k <= 0){
    34             return {};
    35         }
    36         vector<int> result;
    37         int lo = 0,hi = input.size() - 1;
    38         int idx ;
    39         idx = partition(input,lo,hi);//
    40         int target = k - 1;
    41         while(idx != target){            
    42             
    43             if(idx < target){
    44                 lo = idx + 1;
    45                 
    46             }
    47             else if(idx > target){
    48                 hi = idx - 1;
    49             }
    50             idx = partition(input,lo,hi);
    51         }
    52         for(int i = 0;i < k;++i){
    53             result.push_back(input[i]);
    54         }
    55         return result;
    56     }
    57 };

    第二种方法:

    解法2:O(nlogk)的算法,特别适合处理海量数据。

    priority_queue加入和删除操作都是O(logk),top操作是O(1)。默认top的是最大元素。优先级队列本质是基于vector实现的最大堆,因为vector通过下标访问数组,所以top操作复杂度是O(1)的;

    STL的set和map还有就是multise和multimap都是基于红黑树实现的,begin是最小元素,即基于最小堆实现的,只有自己写一个仿函数就可以得到最大堆,注意就重载()就行了,stack和queue都是基于deque。红黑树中查找、删除和插入操作的时间复杂度都是O(logk)。

    如果要使用仿函数要引入头文件functional。才可以使用greater<int>。

    但它是如何保证一棵n个结点的红黑树的高度始终保持在logn的呢?这就引出了红黑树的5个性质:

    1. 每个结点要么是红的要么是黑的。  
    2. 根结点是黑的。  
    3. 每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。  
    4. 如果一个结点是红的,那么它的两个儿子都是黑的。  
    5.  对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。
    #include<iostream>
    #include<vector>
    #include<string>
    #include <cstdio>
    #include<queue>
    #include<algorithm>
    #include<set>
    using namespace std;
    template<typename T>
    struct greater{
        bool operator() (const T &a, const T &b) {
            return a > b;
        }
    };
    
    int main() {    
        multiset<int,greater<int>> hashSet;    
        for (int i = 0; i < 4; ++i) {//输入1,3,55,4
            int a = 0;
            cin >> a;
            hashSet.insert(a);        
        }
        multiset<int>::iterator iter = hashSet.begin();//得到55
        cout << *iter << endl;
        system("pause");
    }
    仿函数最大set
    #include<iostream>
    #include<vector>
    #include<set>
    #include<functional>
    using namespace std;
    int main() {    
        multiset<int,greater<int>> hashSet;    
        for (int i = 0; i < 4; ++i) {//输入1,3,55,4
            int a = 0;
            cin >> a;
            hashSet.insert(a);        
        }
        multiset<int>::iterator iter = hashSet.begin();//得到55
        cout << *iter << endl;
        system("pause");
    }
    使用functional
    class Solution {
    public:   
        vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
            vector<int> result;
            if(input.empty() || k <= 0 || k > input.size()){
                return result;
            }
            multiset<int,greater<int>> hashSet;
            multiset<int,greater<int>>::iterator iter = hashSet.begin();
            for(int i = 0;i < input.size();++i){
                iter = hashSet.begin();
                if(hashSet.size() < k){
                    hashSet.insert(input[i]);
                }
                else{
                    if(*iter > input[i]){
                        hashSet.erase(*iter);
                        hashSet.insert(input[i]);
                    }
                }
            }
            iter = hashSet.begin();
            for(iter;iter != hashSet.end();++iter){
                result.push_back(*iter);
            }
            return result;
        }
    };

    解法3:

    使用priority_queue实现最大堆。(默认是最大堆,即top等于最大的元素,降序);

    底层容器是vector实现的最大堆(stl源码)

    模板:priority_queue<int,vector<int>,greater<int>>,升序,最小堆

    class Solution {
    public:   
        vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
            vector<int> result;
            if(input.empty() || k <= 0 || k > input.size()){
                return result;
            }
            priority_queue<int> q;
            for(int i = 0;i < input.size();++i){
                if(q.size() < k){
                    q.push(input[i]);
                }
                else{
                    if(q.top() > input[i]){
                        q.pop();
                        q.push(input[i]);
                    }
                }
            }
            for(int i = 0;i < k;++i){
                result.push_back(q.top());
                q.pop();
            }
            return result;
        }
    };
  • 相关阅读:
    在awk里引用shell变量(支持正则)
    python模块pyautogui
    一个完整的搜索系统
    信息检索笔记(9)再论文档评分
    信息检索导论学习笔记(8)向量空间模型
    搜索引擎查询扩展
    信息检索笔记(10)Lucene文档评分机制
    Lucene的分析过程
    信息检索导论学习笔记(7)文档评分、词项权重计算
    信息检索导论学习笔记(5)
  • 原文地址:https://www.cnblogs.com/dingxiaoqiang/p/8031843.html
Copyright © 2011-2022 走看看