数据结构-剑指offer-最小的K个数

38 篇文章 0 订阅
38 篇文章 0 订阅

题目:

思路:先排序后输出:

代码1:时间复杂度O(n^2)排序(可使用已有的排序算法,这里使用的是冒泡)。运行结果排序算法有问题

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int len = input.size();
        vector<int> output;
        SortNumbers(input);
        for (int i=0;i<k;i++)
            output.push_back(input[i]);
        return output;
    }
private:
    vector<int> SortNumbers(vector<int> input){
        vector<int> result = input;
        int n = input.size();
        int temp;
        for (int i = 0; i < n - 1; i++){
        // 从后向前依次的比较相邻两个数的大小
            for (int j = 0; j < n - 1; j++){
            // 如果后面的元素小,则交换它们的位置
                if (result[j + 1] < result[j]){
                    temp = result[j + 1];
                    result[j + 1] = result[j];
                    result[j] = temp;
                }
            }
        }
        return result;
    }
};

代码2:时间复杂度O(nlogn)利用全排序函数sort(input.begin(),input.end());

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int len = input.size();
        vector<int> output;
        if( k>len || k<=0 || len<=0)
            return output;
        sort(input.begin(),input.end());
        for (int i=0;i<k;i++)
            output.push_back(input[i]);
        return output;
    }
};

代码3:时间复杂度O(n)利用快排中的获取分割中轴点位置函数。基于数组的第K个数字来调整,则使得比k个数字小的所有数字都位于数字的左边,比第k个数字大的所有数字都位于数组的右边。这样调整后,位于数组中左边的k个数字就是最小的k个数字(这k个数字不一定是排序的)。这种思路在“数组中出现次数超过一半的数字”的题目中出现过,而我在做这道题的时候使用的是哈希表的方法,没有使用这种思路,需要用这种思路再去重新做一遍跟次数相关的题目。但这种解法会修改输入的数组,因为函数getPartition()会改变数组中数字的顺序。

class Solution {
public:
    void swap(int &fir, int &sec){
        int temp = fir;
        fir = sec;
        sec = temp;
    }
    int getPartition(vector<int> &input, int start, int end){
        if(input.empty() || start>end) return -1;
        int temp = input[end];
        int j = start - 1;
        for(int i=start;i<end;i++){
            if(input[i] <= temp){
                j++;
                if(i != j)
                    swap(input[i],input[j]);
            }
        }
        swap(input[j+1],input[end]);
        return (j+1);
    }
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> result;
        if(input.empty() || k>input.size() || k<=0) return result;
        int start  = 0;
        int end = input.size()-1;
        int index = getPartition(input,start,end);
        while(index != k-1){
            if(index > k-1){
                end = index - 1;
                index = getPartition(input,start,end);
            }
            else{
                start = index + 1;
                index = getPartition(input,start,end);
            }
        }
        for(int i=0;i<k;i++){
            result.push_back(input[i]);
        }
        return result;
    }
};

代码4:时间复杂度O(nlogk).代码3的思路会改变原有的数组中数字的顺序,如果题目不允许改变,这样的方法就不能用了。可以使用堆栈的方法,这样的方法很适合处理海量数据。可以先创建一个大小为k的数据容器来存储最小的k个数字,接下来每次从输入的n个整数中读入一个数。如果容器中已有的数字少于k个,则直接把这次读入的整数放入到容器中;如果容器中已有k个数字,也就是容器已满,此时不能再插入新的数字而只能替换已有的数字。找出这已有的k个数中的最大值,然后拿待插入的整数和最大值进行比较。如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还要大,那么这个数不可能是最小的k个数之一,于是抛弃这个数。

我自己先按照这个思路写了一个,但返回值与我第一种方法的一模一样,why????

class Solution {
public:
    int getResultMax(vector<int> input){
        int max = input[0];
        int max_num = 0;
        for(int i=1;i<input.size();i++){
            if(input[i] > max){
                max = input[i];
                max_num = i;
            }
        }
        return max,max_num;
    }
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> result;
        if(input.empty() || k<input.size() || k<=0) return result;
        for(int i=0;i<k;i++){
            result.push_back(input[i]);
        }
        int resultMax = 0;
        int numMax = 0;
        for(int i=k;i<input.size();i++){
            resultMax,numMax = getResultMax(result);
            if(input[i] < resultMax){
                result[numMax] = input[i];
            }
        }
        return result;
    }
};

讨论区的写法(堆方法):

最大堆和最小堆当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆。 当父节点的键值总是小于或等于任何一个子节点的键值时为最小堆

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

剑指offer中的红黑树方法:“红黑树”,它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。

class Solution {
public:
    typedef multiset<int,greater<int>> inSet;
    typedef multiset<int,greater<int>>::iterator setIterator;
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        inSet leastNumbers;
        if(k>input.size()) return vector<int> ();
        vector<int>::iterator iter = input.begin();
        for(; iter!=input.end();iter++){
            if(leastNumbers.size()<k)
                leastNumbers.insert(*iter);
            else{
                setIterator iterGreatest = leastNumbers.begin();
                if(*iterGreatest > *iter){
                    leastNumbers.erase(iterGreatest);
                    leastNumbers.insert(*iter);
                }
            }
        }
        vector<int> ret(leastNumbers.begin(),leastNumbers.end());
        return ret;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值