算法面试_最小的K个数

题目:输入n个整数,找出其中最小的k个数。例如,输入3,6,7,2,1,5,6个数字,则最小的3个数字是1,2,3。

1.首先是用最简单的方法: 把输入的n个整数排序,排序之后位于最前面的k个数就是最小的k个数。这种思路的时间复杂度是O(nlogn),显然时间复杂度太大。

2.我们可以使用排速排序中的思想,使用partition函数进行排序,如果基于第k个数字来调整,则使得比第k个数小的所有数字都位于数组的左边,比第k个数字大的所有数字都位于数组的右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数字(这k个数字不一定是排序的)。

接下来我们来编写C++的代码:

void GetLeastNumbers(int* input, int n, int* output, int k)
{
	if(input == nullptr || output == nullptr || k > n || n <= 0 || k <= 0)
		return;

	int start = 0;
	int end = n - 1;
	int index = partition(input, n, start, end);
	if(index != k-1)
	{
		if(index > k -1)
		{
			end = index - 1;
			index = partition(input, n, start, end);
		}
		else
		{
			start = index + 1;
			index = partition(input, n, start, end);
		}
	}
	
	for(int i =0; i < k; i++)
		output[i] = input[i];
}

这种思路的时间复杂度为O(n),但是采用这个思路有一个限制,那就是我们需要修改输入的数组,因为函数partition会调整数组中数字的顺序。如果面试官要求不能修改数组的话,我们就只能另寻他法。

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

所以,当容器满的时候,我们要进行三个步骤:

  1. 在k个整数中找到最大数。
  2. 有可能在这个容器中删除最大数。
  3. 有可能要插入一个新的数。

如果用一个二叉树来实现这个数据容器,那么我们能在O(logk)时间内实现这三个步骤。所以对于n个输入数字而言,总的时间效率为O(nlogk)。

这里我们选用最大堆

接下来我们编写C++代码:

typedef multiset<int, greater<int>>  intSet;
typedef mulyiset<int, greater<int>>::iterator setIterator;

void GetLeastNumbers(const vector<int>& data, intSet& leastNumbers, int k)
{
	leastNumbers.clear();

	if(k < 1 || data.size() < k)
		return;

	vector<int>::const_iterator iter = data.begin();
	for(; iter != data.end(); ++iter)
	{
		if((leastNumbers.size()) < k)
			leastNumbers.insert(*iter);
		else
		{
			setIterator iterGreatest = leastNumbers.begin();
			
			if(*iter < *(leastNumbers.begin()))
			{
				leastNumbers.erase(iterGreatest);
				leastNumbers.insert(*iter);
			}
		}
	}
}

扩展:

我们还可能在面试的过程中遇到《找出最大的k个数》这样的变形题,他们的思路基本上是一样的,就是将对大堆改为最小堆。

发布了94 篇原创文章 · 获赞 37 · 访问量 3446

猜你喜欢

转载自blog.csdn.net/Rocky6688/article/details/103491741
今日推荐