求一个数组中最小的K个数

面试中遇到的求一个数组中最小的K个数的问题,不仅要求解法,还要求高效。介绍了两种常见的解决方案:排序选择和使用堆。但面试官对这些解法并不满意。文中揭示了《剑指Offer》中的解法,通过快速排序的Partition函数,找到基准数的位置来找到最小的K个数,实现了更优的时间复杂度O(nlogk)。
摘要由CSDN通过智能技术生成

面试的时候,面试官问了这道题“求一个数组中最小的k个数”,我当时只给出了两种解法:

1. 首先使用排序,然后选择前k个值返回。这种算法最好的时间复杂度是O(nlogn),取决于所选择的排序算法

2.初始化一个k个元素的数组a,首先将数组中前k个元素放入a中,然后从K+1到最后一个元素进行如下判断:如果当前元素大于a中最大元素,继续向后遍历;如果当前元素小于a中最大元素,则替换a中最大元素.......就可以得到最小的k个数,这种算法时间复杂度可以为O(nk)。如果采用堆作为存储K个元素的容器,建堆的时间为O(k),获取堆的最大值O(1),替换最大元素后,调整堆的时间复杂度为O(logk),所以最终时间复杂度为O(nlogk),适合海量数据获取k个最大数的情况。

上面说的两种算法,面试官都不满意,等面试结束后,在网上查了一下,这就是剑指offer上面的题目。下面说一下剑指offer上面的解法。

题目并没有要求返回有序的前k个数,如数组:4,5,1,6,2,7,3,8。返回最小的4个数,结果应该为1,2,3,4(这个可以是无序的)。

在 C++ ,要找到数组中所有数字分成两半的最大差值,可以使用一种叫做“分治法”的算法,如快速选择(Quickselect)。这种算法类似于快速排序,但是只需要对一部分元素进行排序,目的是找到第 k 小的元素。在这个问题,我们可以找间位置的数,然后将数组一分为二,分别计算左右部分的最大差值。 以下是简单的步骤: 1. 首先,我们需要选择一个基准元素(通常是间元素),并将数组分为两个部分:小于等于基准的部分和大于基准的部分。 2. 如果数组长度是奇数,基准就是间那个数;如果是偶数,取间两个数的平均值作为基准。 3. 比较基准值和目标大小(即要找到的最小差的一半),如果差距大于目标,那么较大的那一半肯定比另一半更能满足条件。 4. 如果差距不大于目标,则在较小的那一半继续应用上述步骤,直到找到符合条件的结果。 下面是一个基本的伪代码框架: ```cpp int partition(int arr[], int low, int high) { // ... 分区操作... } int findMedianTwoSumDiff(int arr[], int n, int target) { if (n == 0) return 0; if (n % 2 == 0) { // 如果数组长度是偶数 int median_index = n / 2 - 1; return min(findMedianTwoSumDiff(arr, median_index, target), findMedianTwoSumDiff(arr + median_index + 1, n - median_index - 1, target)); } int pivot_index = n / 2; // 如果数组长度是奇数 int pivot = arr[pivot_index]; int left = partition(arr, low, pivot_index); int right = partition(arr, pivot_index + 1, high); // ... 判断并递归处理左、右两部分... } // ... 实现 partition 函数 ... ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值