数组--5-最小的K个数

题目

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

思路

1、(array被改变了)结合数组-4的第一种类似快排partion的思想。最小的k个数,那么找到第k个数,其左边就是最小的k个数  (不是有序的),所以时间复杂度是O(N), 快排的结果是base两边都是有序的,时间复杂度是O(NlogN)。

    快排是对base两边都递归下去,这个是只判断一边。


2、(array未被改变)先创建一个大小为k的数据容器来存储最小的k个数字,接下来我们每次从输入的n个整数中的n个整数中读入一个数。如果容器中已有的数字少于k个,则直接把这次读入的整数放入容器之中;如果容器已经有k个数字了,也就是容器满了,此时我们不能再插入新的数字而只能替换已有的数字。找出这已有的k个数中的最大值,然后拿这次待插入的整数和最大值进行比较。如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还要大,那么这个数不可能是最小的k个整数之一,于是我们可以抛弃这个整数。

因此当容器满了之后,我们要做3件事情:一是在k个整数中找到最大数;二是有可能在这个容器中删除最大数;三是有可能要插入一个新的数字。如果用一个二叉树来实现这个数据容器,那么我们在O(logk)时间内实现这三步操作。因此对于n个输入数字而言,总的时间效率就是O(nlogk)

可以建立大根堆来实现

        make_heap 将[start, end)范围进行堆排序,默认使用less, 即最大元素放在第一个

        pop_heap   将front(即第一个最大元素)移动到end的前部,同时将剩下的元素重新构造成(堆排序)一个新的heap。

        push_heap 对刚插入的(尾部)元素做堆排序。

扫描二维码关注公众号,回复: 2003649 查看本文章

        sort_heap   将一个堆做排序,最终成为一个有序的系列,可以看到sort_heap时,必须先是一个堆(两个特性:1、最大元素在第一个 2、添加或者删除元素以对数时间,因此必须先做一次make_heap.


3、直接使用红黑树来实现,选用multiset,允许集合内数字重复。 O(NlogK)

#include <iostream>
#include <vector>
using namespace std;

class Solution
{
public:
	vector<int> minKnumber(vector<int> &array, int k)
	{
		vector<int> result;
		int len = array.size();
		if (len == 0 || k <= 0 || k > len)
			return result;

		int start = 0;
		int end = len - 1;
		int index = partion(array, start, end);
		while (index != k - 1)
		{
			if (index > k - 1)
				index = partion(array, start, index - 1);
			else
				index = partion(array, index + 1, end);
		}
		for (int i = 0; i < k; i++)
		{
			result.push_back(array[i]);
		}
		return result;
	}
private:
	int partion(vector<int> &array, int left, int right)
	{
		int baseNum = array[left];
		while (left < right)
		{
			while (left < right && array[right] >= baseNum)
				right--;
			array[left] = array[right];
			while (left < right && array[left] <= baseNum)
				left++;
			array[right] = array[left];
		}
		array[left] = baseNum;
		return left;
	}
};

int main()
{
	Solution s;
	vector<int> array{4, 5, 1, 6, 2, 7, 3, 8};
	vector<int> result = s.minKnumber(array, 1);
	for (auto i : result)
		cout << i;
	cout << endl;
	system("pause");
	return 0;

}


#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

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

		vector<int> result(array.begin(), array.begin() + k);
		make_heap(result.begin(), result.end());				//建堆,将前 k 个数存在result中,默认大根堆
		for (int i = k; i < len; i++)
		{
			if (array[i] < result[0])							//如果有元素比堆中最大的都大
			{
				pop_heap(result.begin(), result.end());			//先把堆中最大的移到最后面,然后再pop出去
				result.pop_back();
				result.push_back(array[i]);						//将新的元素push进来,再调整堆
				push_heap(result.begin(), result.end());
			}
		}
		sort(result.begin(), result.end());						//对堆排序,使其从小到大输出
		return result;
	}
};


#include <iostream>
#include <set>
#include <vector>
#include <functional>
using namespace std;

class Solution
{
public:
	//不改变原始数组,用红黑树的multiset实现
	vector<int> getLeastNumbers( vector<int> &array, int k)
	{
		vector<int> result;
		int len = array.size();
		if (len <= 0 || k <= 0 || k > len)
			return result;

		multiset<int, greater<int> > leastNumber;
		vector<int>::iterator vec_it = array.begin();
		for (; vec_it != array.end(); vec_it++)
		{
			if (leastNumber.size() < k)
				leastNumber.insert(*vec_it);
			else
			{
				multiset<int, greater<int>>::iterator great_it = leastNumber.begin();
				if (*vec_it < *great_it)
				{
					leastNumber.erase(*great_it);
					leastNumber.insert(*vec_it);
				}
			}
		}
		return vector<int>(leastNumber.begin(), leastNumber.end());
	}
};

int main()
{
	Solution s;
	vector<int> array{2, 3, 2, 4, 2, 9, 7, 4};
	vector<int> result = s.getLeastNumbers(array, 6);
	for (auto i : result)
		cout << i;
	cout << endl;
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ax_hacker/article/details/80946185
今日推荐