剑指Offer----面试题30:最小的K个数

题目:

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

方法一:


时间复杂度为O(nlongn)且改变了原来数组,不推荐。

分析:首先通过快速排序算法对数组元素进行排序,然后依次输出其中的前k个数。

代码《略》

方法二:


分析:使用Partation函数,使时间复杂度为O(n),如果基于数组的第K个数字来调整,使得比第K个数字小的所有数字都位于数组的左边,比第K个数字大的所有数字都位于数组的右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数字。

注意:
  1. 输出的这k个数字不一定是排序的;
  2. 原始数组发生了改变!

源代码如下:

#include<iostream>
#include<cstdlib>

using std::cout;
using std::endl;


class ThrowError{};

void show(int *arr, int n)
{
	for (int i = 0; i < n; i++)
	{
		cout << arr[i] << "  ";
	}

	cout << endl;
}

void Swap(int *m, int *n)
{
	int temp = *m;
	*m = *n;
	*n = temp;
}

//返回一个数组下标,该下标左边的数字都是小于该下标对应的值,右边的数字都大于该下标所对应的值
int Partiton(int *arr, int length, int start, int end)
{
	if (arr == NULL || length <= 0 || start < 0 || end >= length)
		throw ThrowError{};

	int index = rand() % (end - start + 1) + start;
	Swap(&arr[index], &arr[end]);

	int small = start - 1;
	for (int j = start; j < end; ++j)
	{
		if (arr[j] < arr[end])
		{
			++small;
			if (small != j)
				Swap(&arr[small], &arr[j]);
		}
	}

	++small;
	Swap(&arr[small], &arr[end]);

	return small;
}

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

	int start = 0;
	int end = n - 1;
	int index = Partiton(arr, n, start, end);
	while (index != k - 1)
	{
		if (index < k - 1)//说明index在k的左边,需要对右边进行递归
		{
			start = index + 1;
			index = Partiton(arr, n, start, end);
		}
		else//说明index在k的右边,需要对左边进行递归
		{
			end = index - 1;
			index = Partiton(arr, n, start, end);
		}
	}

	for (int i = 0; i < k; i++)
	{
		output[i] = arr[i];
	}
}

void test11()
{
	int arr[] = { 4, 5, 1, 6, 2, 7, 3, 8 };
	int output[4] = { 0 };
	GetLeastNumbers(arr, 8, output, 4);
	show(output, 4);
}

int main()
{
	test11();

	system("pause");
	return 0;
}

运行结果如下:
1  2  3  4
请按任意键继续. . .

方法二:



源代码如下:

#include<iostream>
#include<set>
#include<vector>
#include<functional>

using std::endl;
using std::cout;
using std::vector;
using std::multiset;
using std::greater;

void GetLeastNumbers2(const vector<int> &vec, multiset<int, greater<int>> &leastNumbers, size_t k)
{
	if (vec.empty() || vec.size() < k)
		return;

	leastNumbers.clear();

	for (auto iter = vec.cbegin(); iter != vec.cend(); ++iter)
	{
		if (leastNumbers.size() < k)
			leastNumbers.insert(*iter);
		else
		{
			auto leastIter = leastNumbers.begin();
			if (*leastIter > *iter)
			{
				leastNumbers.erase(*leastIter);
				leastNumbers.insert(*iter);
			}
		}
	}
}


void test21()
{
	vector<int> vec = { 4, 5, 1, 6, 2, 7, 3, 8 };
	multiset<int, greater<int>> leastNumbers;

	GetLeastNumbers2(vec, leastNumbers, 4);

	for (auto iter = leastNumbers.begin(); iter != leastNumbers.end(); ++iter)
		cout << *iter << "  ";

	cout << endl;
}

int main()
{
	test21();

	system("pause");
	return 0;
}


运行结果:
4  3  2  1
请按任意键继续. . .



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值