剑指offer第40题:最小的K个数

输入N个整数,寻找其中最小的k个数。

方法1:利用Partition函数,找到位于第k-1坐标的数,则它左边的数以及它自己就是要返回的k个数。

class Solution {
public:
	void swap(int &fir, int &sec)
	{
		int temp = fir;
		fir = sec;
		sec = temp;
	}

	int getPartition(vector<int> & numbers, int start, int end) {
		//int index = rand()%(end-start+1)+start;
		//swap(numbers[index], numbers[end]);
		int small = start - 1;
		for (int index = start; index<end; ++index) {
			if (numbers[index]<numbers[end]) {
				++small;
				if (small != index) {
					swap(numbers[index], numbers[small]);
				}
			}
		}
		++small;
		swap(numbers[small], numbers[end]);
		return small;
	}

	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;
	}
};

该方法的时间复杂度为O(n),该方法的缺点是会修改原有数组,并且在输入数据量十分大的时候,可能不能一次读入内存。

注意因为在Partition的过程中要修改原有数组,所以getPartition函数要传入vector的引用。

方法二:

基于最小堆(红黑树)的方法。

我们基于最小堆来实现,我们可以以O(1)的时间获得k个数字中的最大值,但需要O(logk)时间完成删除及插入操作。

我们用C++模板中的multiset完成,multiset本质是由红黑树实现的。

#include<set>
class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        multiset<int, greater<int>> leastNumbers;
        vector<int> vc;
        if(k>input.size())
            return vc;
        for (int i = 0; i<input.size(); i++) {
            if (leastNumbers.size()<k)
                leastNumbers.insert(input[i]);
            else {
                if (input[i]<*leastNumbers.begin()) {
                    leastNumbers.erase(leastNumbers.begin());
                    leastNumbers.insert(input[i]);
                }
            }
        }
        auto it = leastNumbers.begin();
        for(;it!=leastNumbers.end();it++)
            vc.push_back(*it);
        return vc;
    }
};

该方法的时间复杂度为O(nlogk),该方法的优点是不需要修改原有数组,并且十分适合实时处理数据,因为该方法不用一次读入所有数据。

方法三:自己建立堆

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int len=input.size();
        if(len<=0||k>len||k<=0) return vector<int>();
         
        vector<int> res(input.begin(),input.begin()+k);
        //建堆
        make_heap(res.begin(),res.end());
         
        for(int i=k;i<len;i++)
        {
            if(input[i]<res[0])
            {
                //先pop,然后在容器中删除
                pop_heap(res.begin(),res.end());
                res.pop_back();
                //先在容器中加入,再push
                res.push_back(input[i]);
                push_heap(res.begin(),res.end());
            }
        }
        //使其从小到大输出
        //sort_heap(res.begin(),res.end());
         
        return res;
         
    }
};

方法四:建立最小堆

其实这样做没意义,因为建立最小堆是遍历完所有数然后建立的,建立完以后再连续pop k次即可。

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

		vector<int> res;
		auto cmp = [](const int x, const int y) { return x > y; };
		//建堆
		make_heap(input.begin(), input.end(),cmp);

		for (int i = 0; i<k; i++) {
			pop_heap(input.begin(), input.end(),cmp);
			res.push_back(*(input.end() - 1));
			input.pop_back();
		}

		return res;

	}
};

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值