最小的k个数字

/*****************************************************************
题目:输入n个整数,找出其中最小的k个数。例如输入4,5,1,6,2,7,3,8这
8个数字,则最小的4个数字是1,2,3,4。
*****************************************************************/
#include<iostream>
#include<set>
#include<vector>

using namespace std;

void swap(int* pNum1, int* pNum2)
{
	int nTemp = *pNum1;
	*pNum1 = *pNum2;
	*pNum2 = nTemp;
}

int partition(int* numbers, int start, int end)
{
	if(numbers == NULL || start>end)
		throw new std::exception("invalid input!\n");

	int standard = numbers[end];
	int small = start-1;

	for(int i=start; i<end; ++i)
	{
		if(numbers[i] < numbers[end])
		{
			++small;
			if(i != small)
			swap(&numbers[i],&numbers[small]);
		}
	}

	++small;
	swap(&numbers[small], &numbers[end]);
	return small;
}
//方法1
//按照第29题的思路,可以给予partition来解决这个问题
//如果基于数组的第k个数字来调整,使得第比第k个数字小的所有
//数字都位于数组的左边,比第k个数字大的所有数字都位于数组的
//右边。这样调整后,位于数组中左边的k个数字就是最小的k个数
//时间复杂度为O(N)
void GetLeastNumbers(int* input,int n, int* output, int k)
{
	if(input == NULL || n<=0 || output == NULL || k<=0 || k>n)
		throw std::exception("invalid question!");

	int start = 0;
	int end = n-1;

	int index = partition(input,start,end);
	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);
		}
	}
	for(int i=0; i<k; ++i)
	{
		output[i] = input[i];
	}
}

//方法2:特别适合处理海量数据
//用堆或者红黑树实现。先填满容器k个元素,后面的数字如果大于容器中最大值,、
//就将容器中最大值删除,加入新元素。
//这里采用multiset解决问题,它是由红黑树实现的
typedef multiset<int,greater<int>> intSet;
typedef multiset<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 = leastNumber.begin();

			if(*iter < *(leastNumbers.begin()))
			{
				leastNumbers.erase(iterGreatest);
				leastNumbers.inset(*iter);
			}
		}
	}
}

void test()
{
	const int length = 8;
	int input[length] = {4,5,1,6,2,7,3,8};
	const int k = 4;
	int output[k];
	GetLeastNumbers(NULL,0,output,k);
	for(int i=0; i<k; ++i)
	{
		printf("%d\t",output[i]);
	}
}
int main()
{
	try{
	test();
	}
	catch(std::exception ex)
	{
		std::cerr<<ex.what();
	}
	return 0;
}
第一种方法复杂度第,但要改变输入的数据;而第二种方法不会改变输入的数据适用于n很大,k较小的问题

==参考剑指offer

### 头歌平台中的“最小的K个数”算法实现 在头歌平台上,“最小的K个数”是一个经典的算法问题,通常可以通过多种方法来解决。以下是几种常见的解决方案及其对应的代码示例。 #### 方法一:基于堆排序的解法 利用最大堆(Max Heap),我们可以高效地找出数组中最小的 `k` 个数。具体来说,先构建一个大小为 `k` 的最大堆,随后遍历剩余元素并堆顶比较。如果当前元素小于堆顶,则替换堆顶并重新调整堆结构。 ```python import heapq def get_least_numbers(nums, k): if k == 0: return [] heap = [] # 创建一个空的最大堆 for num in nums[:k]: heapq.heappush(heap, -num) # 使用负号将小根堆变为大根堆 for num in nums[k:]: if -heap[0] > num: # 如果当前数字比堆顶小 heapq.heapreplace(heap, -num) # 替换堆顶并调整堆 result = [-x for x in heap] return sorted(result) # 测试用例 nums = [3, 2, 1, 5, 6, 4] k = 2 print(get_least_numbers(nums, k)) # 输出 [1, 2] ``` 这种方法的时间复杂度主要由堆的操作决定,整体复杂度约为 \( O(n \log k) \)[^1]。 --- #### 方法二:快速选择算法 快速选择是一种基于分治思想的算法,类似于快速排序的思想,但它只处理目标区间的一侧。通过一次分区操作即可缩小范围,从而减少不必要的计算量。 ```python def partition(arr, low, high): pivot = arr[high] i = low - 1 for j in range(low, high): if arr[j] <= pivot: i += 1 arr[i], arr[j] = arr[j], arr[i] arr[i + 1], arr[high] = arr[high], arr[i + 1] return i + 1 def quick_select(arr, low, high, k): if low < high: pi = partition(arr, low, high) if pi == k: return arr[:pi] elif pi < k: return quick_select(arr, pi + 1, high, k) else: return quick_select(arr, low, pi - 1, k) def get_least_numbers_quickselect(nums, k): if not nums or k == 0: return [] return quick_select(nums, 0, len(nums) - 1, k) # 测试用例 nums = [3, 2, 1, 5, 6, 4] k = 2 result = get_least_numbers_quickselect(nums.copy(), k) print(sorted(result)) # 输出 [1, 2] ``` 此方法的平均时间复杂度为 \( O(n) \),但在最坏情况下可能退化到 \( O(n^2) \)[^3]。 --- #### 方法三:直接排序 对于简单场景,可以直接对整个数组进行升序排列,然后取前 `k` 个元素。虽然效率较低,但对于小型数据集仍然适用。 ```python def get_least_numbers_sorting(nums, k): if k == 0: return [] return sorted(nums)[:k] # 测试用例 nums = [3, 2, 1, 5, 6, 4] k = 2 print(get_least_numbers_sorting(nums, k)) # 输出 [1, 2] ``` 该方法的时间复杂度为 \( O(n \log n) \)[^2]。 --- ### 总结 上述三种方法各有优缺点: - 堆排序适合大规模数据且内存有限的情况; - 快速选择适用于追求高效率的大规模数据; - 排序方法则更适合于教学目的或小规模数据测试。 最终的选择应根据实际需求权衡性能可读性等因素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值