• [剑指Offer]40-最小的k个数


    题目链接

    https://www.nowcoder.com/practice/6a296eb82cf844ca8539b57c23e6e9bf?tpId=13&tqId=11182&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

    题意

    输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的四个数字是1,2,3,4,

    解题思路

    法一:若可以修改输入数据:时间复杂度O(n)。
    利用快排的partition数组。第一遍以后partion的范围要想清楚,"是一个小小的范围",这样才能实现时间复杂度O(n)。
    注意:1、特判一定要全!2、瞎throw容易看不到真正的错误提示... 3、各种边界填写的变量要过脑子...

    法二:若不可以修改输入数据,或是要处理海量数据(内存较小):时间复杂度O(nlogk),内存要求可容纳大小为k的数组即可。

    • 可以维护一个大小为k的数组。
    • 容器满了后,每次再来一个数,若大于容器内最大值,则删除、插入新值(即替换),若小于容器内最大值,则忽略。
    • 最终得到的数组k即是最小的k个

    使用红黑树实现以上算法。
    特别地,由于直接替换节点可能破坏红黑树的结构,所以红黑树不支持直接改变元素值,必须要删除旧值、插入新值来实现。

    相关知识

    红黑树
    • 红黑树是特殊的二叉查找树,红黑节点保证最长路径<=2*最短路径。红黑树是自动有序的。

    • 红黑树不严格满足二叉平衡树(AVL)左右子树高度最多相差1的条件。?具体

    • 红黑树的查找、插入、删除时间复杂度都是O(logk)。?具体

    • STL中的set和multiset都是用红黑树实现,其中multiset可有重复元素。

    比较仿函数greater 与less (即可以当作函数一样使用)
    • typedef multiset<int,greater<int>> intSet中,greater实质是一个结构体,greater表示内置类型从大到小排序,less表示内置类型从小到大排序。它们也可以用作sort函数的比较器。
    • set与multiset中默认使用less,即由小到大排序。
    最大堆

    最大堆中,根结点的值总是大于它的子树中任意节点的值。
    得到最大值O(1)、插入、删除时间复杂度都是O(logk)。

    代码

    法一代码

    class Solution {
    public:
        vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
            vector<int> minNums;
            if(input.size()!=0&&k>=1&&k<=input.size()){//!!!写全
                size_t beg=0;
                size_t end=input.size()-1;
                size_t index=partition(input,beg,end);//
                while(index!=k-1){//
                    if(index<k-1){
                        beg=index+1;//
                        index=partition(input,beg,end);//
                    }
                    else{
                        end=index-1;//
                        index=partition(input,beg,end);//
                    }
                }
                for(int i=0;i<k;i++){
                    minNums.push_back(input[i]);
                }
            }
            return minNums;
        }
    private:
        size_t partition(vector<int> &input,size_t beg,size_t end){
            if(!input.size()||end<beg||beg<0){
                throw "input error!";
            }
            size_t index=random(beg,end);
            swap(input[index],input[beg]);//
            int temp=input[beg];
            
            size_t i=beg;
            size_t j=end;
            while(i<j){
                while(i<j&&input[j]>=temp){
                    --j;
                }
                if(i!=j){
                    input[i]=input[j];
                    ++i;
                }
                while(i<j&&input[i]<=temp){
                    ++i;
                }
                if(i!=j){
                    input[j]=input[i];
                    --j;
                }
            }
            input[i]=temp;
            return i;
        }
        
        void swap(int& a,int& b){
            int temp=a;
            a=b;
            b=temp;
        }
        
        size_t random(size_t beg,size_t end){
            if(end<beg){
                throw "input error!";
            }
            srand((unsigned) time(0));
            return beg+rand()%(end-beg+1);
        }
    };
    

    法二代码

    class Solution {
    public:
        vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
            vector<int> minVec;
            typedef multiset<int,greater<int>> intSet;
            intSet minSet;
            if(input.size()&&k>0&&k<=input.size()){
                for(auto it=input.begin();it!=input.end();++it){
                    if(minSet.size()!=k){
                        minSet.insert(*it);
                    }
                    else{
                        if(*minSet.begin()>*it){
                            minSet.erase(minSet.begin());
                            minSet.insert(*it);
                        }
                    }
                }
            }
            for(auto it=minSet.begin();it!=minSet.end();++it){
                minVec.push_back(*it);
            }
            return minVec;
        }
    };
    
  • 相关阅读:
    指针变量的*p,p以及&p的区别
    C 真正理解二级指针
    二叉树Bynary_Tree(2):二叉树的递归遍历
    二叉树Binary_Tree(1):二叉树及其数组实现
    栈stack(2):栈的链表实现
    栈stack(1):栈的数组实现
    队列queue(2):链表实现队列
    老猿学5G扫盲贴:3GPP规范中与计费相关的主要规范文档列表及下载链接
    老猿学5G扫盲贴:推荐三篇介绍HTTP2协议相关的文章
    老猿学5G扫盲贴:中移动的5G计费架构中Nchf'服务化接口以及CHF中的AGF
  • 原文地址:https://www.cnblogs.com/coding-gaga/p/10542651.html
Copyright © 2020-2023  润新知