剑指offer40 最小的k个数

题目描述

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

关键:引用!!!!!!!!!!!!!!

方法一:快排思想,时间复杂度O(n),修改了数组(改进的快排无法通过???疑惑——因为是用low做枢轴,所以必须先high--,从右边开始移动指针!!!!!!!!!!!!!!

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> ans;
        if(input.size()==0||k<=0 ||input.size()<k) return ans;
        int start=0,end=input.size()-1;
        int index=Partion(input,start,end);
        while(index!=k-1)
        {
            if(index>k-1)
            {
                end=index-1;
                index=Partion(input,start,end);
            }
            else
            {
                start=index+1;
                index=Partion(input,start,end);
            }
        }
        for(int i=0;i<k;i++)
            ans.push_back(input[i]);//改变了输入的数组,时间复杂度O(n),运用了快排的思想
        return ans;
    }

    int Partion(vector<int> &input,int low,int high)//引用很关键!!!!!!!
    {
        //if(input.empty() || low>high) return -1;
        int pivot=input[high];
        int i=low-1;
        for(int j=low;j<high;j++)
        {
            if(input[j]<=pivot)
            {
                i++;
                if(i!=j) 
                    swap(input[i],input[j]);
            }
        }
        swap(input[high],input[i+1]);
        return i+1;
    }

    int Partion1(vector<int> &input,int low,int high)
    {
        int pivot=input[low];
        while(low<high)
        {
            while(low<high && input[high]>=pivot)
                high--;
            input[low]=input[high];
            while(low<high && input[low]<=pivot)
                low++;
            input[high]=input[low];
        }
        input[low]=pivot;
        return low;
    }
};

方法二:堆排序,时间复杂度O(nlogk),没有修改数组,适合海量数据

大顶堆,适用于升序;小顶堆,适用于降序

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> ans;
        if(input.size()==0||k<=0 ||input.size()<k) return ans;
        //初始化堆,i从最后一个父节点开始调整,满足大顶堆条件(注:为什么用k来代替input.size()?因为假设有海量数据,调整整个堆太复杂)
        for(int i=k/2-1;i>=0;i--)
        {
            adjustHeap(input,i,i+k);
        }
        //从第k个元素开始分别与最大堆的最大值做比较,如果比最大值小,则替换并调整堆。
        //最终堆里的就是最小的K个数。
        for(int i=k;i<input.size();i++)
        {
            if(input[i]<input[0])
            {
                swap(input[i],input[0]);//堆首(最大值)和堆尾互换
                adjustHeap(input,0,k-1);//k个数的剩余部分继续调整成大顶堆
            }              
        }
        for(int i=0;i<k;i++)          
          ans.push_back(input[i]);
        return ans;        
    }
    void adjustHeap(vector<int> &input, int start,int end)//调整堆(大顶堆)
    {
        int dad=start;
        int son=dad*2+1;
        while(son<=end)
        {
            if(son+1<=end && input[son]<input[son+1])
                son=son+1;
            if(input[dad]>input[son])
                return;
            else
            {
                swap(input[dad],input[son]);
                dad=son;
                son=2*dad+1;
            }
        }
    }
};

方法三:堆排序,运用STL标准库函数heap(其实不属于标准库,调用需要#include<algorithm>),没有修改数组,适合海量数据

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> result;
        if(input.size()==0||k<=0 ||input.size()<k) return result;
        for(int i=0;i<k;i++)
            result.push_back(input[i]);
        make_heap(result.begin(),result.end());
        for(int i=k;i<input.size();i++)
        {
            if(input[i]<result[0])
            {
                pop_heap(result.begin(),result.end());//弹出heap顶元素
                result.pop_back();
                result.push_back(input[i]);
                push_heap(result.begin(),result.end());
            }
        }
        sort_heap(result.begin(),result.end());
        return result;
    }
};

方法四:红黑树,运用STL标准库函数multiset结构

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> result;
        if(input.size()==0||k<=0 ||input.size()<k) return result;

        multiset<int,greater<int>> ans;//找到set中的最大值,即由大到小排序
        for(auto it=input.begin();it!=input.end();it++)
        {
            if(ans.size()<k)//set里个数不足k,直接插入数据
            {
                ans.insert(*it);
            }
            else
            {
                auto max=ans.begin();//set里降序排列,取最大值
                if( *it < *(ans.begin()) )
                {
                    ans.erase(max);
                    ans.insert(*it);
                }
            }
        }
        for(auto it=ans.begin();it!=ans.end();it++)
        {
            result.push_back(*it);
        }
        return result;
    }
};

猜你喜欢

转载自blog.csdn.net/starluqifei/article/details/89473944
今日推荐