剑指offer-40:最小的k个数

本文介绍了两种寻找数组中最小K个数的算法。第一种使用Partition排序,通过快速排序的思想找到第K个数的位置,从而确定最小的K个数。第二种算法通过建立最大堆,不断比较并调整堆顶元素,最终得到最小的K个数。文章详细解释了两种算法的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题的题目为:输入你个整数,找到其中最小的K个数。

解题思路如下:

1.数组对于输入的input数组,利用Partition排序对基于k的input数组对齐进行调整,调整后的input数组中位于第k个数的左边的数都小于k,右边的数都大于k。于是k左边的4个数就是最小的k个数,输出即可。

代码如下:

void Swap(int *a, int *b)
{
	int t = *a;
	*a = *b;
	*b = t;
}
//Partition排序
int Partition(int* input, int start, int end)
{
	
	int begin = start;
	int last = end;
	while (begin<last)
	{
		while ((begin < last) && (input[begin] <= input[end]))
			begin++;
		while ((begin<last) && (input[last] >= input[end]))
			last--;
		Swap(&input[begin], &input[last]);
	}
	Swap(&input[begin], &input[end]);
	return begin;
}
void MinKNumber1(int* input, int* output, int length, int k)
{
	assert(input&&output);
	if (length <= 0 || k <= 0 || k > length)
		return;
	int start = 0;
	int end = length - 1;
	//第一次快速排序
	int index = Partition(input, start, end);
	//根据二分思想找以k-1为基准的一次快排
	while (index != k - 1)
	{
		if (index > k - 1)
		{
			end = index - 1;
			index = Partition(input, start, end);
		}
		else
		{
			start = index + 1;
			index = Partition(input, start, end);
		}
	}
	//打印最小的k个数
	for (int i = 0; i < k; i++)
	{
		output[i] = input[i];
		printf("%d ", output[i]);
	}
}

但是基/Partition排序这种算法的实现会改变输入的input数组,并入适用于数据量较大的实现。所以针对本题算法做了如下改进:首先利用已输入input数组中前k个元素建立一个K个数的最大堆,从第k个数开始,每次拿一个数和堆顶元素比较,只有当这个数比堆顶元素小,则与堆顶元素交换,然后在向下调整一次建成新的大堆,直到然后遍历所有的数为止。

代码如下:

void   AdjustDown(int array[], int size, int root)
{
	int left = 2 * root + 1;
	int right = 2 * root + 2;
	if (left >= size)
	{
		return;
	}
	int max = left;
	if (right<size&&array[right]>array[left])
	{
		max = right;
	}
	if (array[root] >= array[max])
	{
		return;
	}
	Swap(array + root, array + max);
	AdjustDown(array, size, max);
}
void  CreateHeap(int array[], int size)
{
	for (int i = size / 2 - 1; i >= 0; i--)
	{
		AdjustDown(array, size, i);
	}
}
//时间复杂度O(nlogn)
void MinKNumber2(int* input, int len, int k)
{
	assert(input);
	int i = 0;
	//1.利用前K个数建大堆
	CreateHeap(input, k);
	//2.遍历后边的数,如果小于堆顶元素则入堆
	for (int j = k; j < len; j++)
	{
		if (input[j]<input[0])
		{
			Swap(&input[0], &input[j]);
			AdjustDown(input, k, 0);

		}
	}
	for (int i = 0; i < k; i++)
	{
		Swap(&input[0], &input[k - i - 1]);
		AdjustDown(input, k - i - 1, 0);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值