找出无序数组中最小的前k个数

本文介绍了一种基于快速排序的改进算法,用于在数组中高效查找第K大的数及前K大数的方法。该算法平均时间复杂度为O(N),通过随机选择基准并分区,递归地缩小搜索范围。

基本思想:在快速排序的基础上进行改进。

时间复杂度:O(nlogn)。

具体代码如下:

package test;

public class Test {
	
	public static int N = 4; //找出最小的4个数
	public static void QuickSort(int a[],int left,int right){
		int i=left;
		int j=right;
		int temp = a[i];
		if(left>=right)
			return ;
		while(i<j){
			while(i<j&&a[j]>temp)
				j--;
			if(i<j){
				a[i++]=a[j];
			}
			while(i<j&&a[i]<temp){
				i++;
			}
			if(i<j){
				a[j--]=a[i];
			}
		}
		a[j]=temp;
		
		if(i>N && left<N)  //在中轴数左边继续寻找
			QuickSort(a,left,i-1);
		
		if(i<=N && right>=N)  //在中轴数右边继续寻找
		    QuickSort(a,i+1,right);
		
	}
	

	public static void main(String[] args) {
		
		int array[] = { 1, 5, 2, 9, 4, 3, 7, 8, 6, 10 };
		
		QuickSort(array,0,N);
		
		for(int i=0;i<N;i++)
			System.out.print(array[i]+" ");
		//System.out.print(Arrays.toString(array));
	}

}

寻找无序数组中的第K大数和前K大数,两个问题互相可以转化。如果可以找到第K大数,那么只再需要O(N)就可以找齐剩余的前K大数。如果可以找到前K大数,那么只再需要O(K)就可以找到第K大数。

先排序,在找第K个。O(NlgN)
快速排序的思想,可以做到平均效率O(N)
随机选一个元素,把所有小于等于这个元素的数移到左边,所有大于这个元素的数移动到右边。如果这个元素成了第K个数,直接返回这个数。
如果左边的个数大于K,不管右边的数了,在左边重复上面的过程。
如果左边的个数等于T<K,不管左边的数了,重复上面的过程,只是K=K-T-1。
平均情况下,第一次划分的时间复杂度是O(N),第二次是O(N/2),总共是O(N+N/2+N/4+...)=O(N)
package test;

public class Test {
	
	public static int QuickSort(int a[],int left,int right,int K){
		int i=left;
		int j=right;
		if(K>right-left+1) 
			return -1;
		if(left>right)
			return -1;
		
		int temp = a[i];
		while(i<j){
			while(i<j&&a[j]>temp)
				j--;
			if(i<j){
				a[i++]=a[j];
			}
			while(i<j&&a[i]<temp){
				i++;
			}
			if(i<j){
				a[j--]=a[i];
			}
		}
		a[i]=temp;
		
		int move = i-left+1;  //已经移动的步数,关键!
		
		if(move==K){
			return a[i];
		}
		else if(move>K){
			return QuickSort(a,left,i-1,K);
		}
		else{
			return QuickSort(a,i+1,right,K-move);
		}
		
	}
	

	public static void main(String[] args) {
		
		int array[] = { 1, 5, 2, 9, 4, 3, 7, 8, 6, 10 };
		
		int k = 5;
		System.out.println(QuickSort(array,0,9,k));
		
	}

}


要解决“输入一个无序数组,输入一个 K 值,输出最小的 K 个数”这个问题,有多种高效的 C++ 实现方式。下面介绍一种使用 **最小堆(priority_queue)** 的方法,时间复杂度为 **O(n + k log n)**,适用于大多数场景。 --- ### ✅ 解题思路: 1. **构建最小堆**:将数组中的所有元素插入到最小堆中。 2. **取出 K 个最小元素**:从堆顶依次取出 K 次元素,即为最小的 K 个数。 --- ### ✅ C++代码实现: ```cpp #include <iostream> #include <vector> #include <queue> #include <algorithm> std::vector<int> findSmallestKNumbers(const std::vector<int>& nums, int k) { std::vector<int> result; if (k <= 0 || nums.empty()) return result; // 使用最小堆 std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap(nums.begin(), nums.end()); // 取出 k 小的元素 for (int i = 0; i < k && !minHeap.empty(); ++i) { result.push_back(minHeap.top()); minHeap.pop(); } return result; } int main() { int n, k; std::cout << "请输入数组长度 n: "; std::cin >> n; std::vector<int> nums(n); std::cout << "请输入数组元素(空格分隔): "; for (int i = 0; i < n; ++i) { std::cin >> nums[i]; } std::cout << "请输入 K 值: "; std::cin >> k; std::vector<int> smallestK = findSmallestKNumbers(nums, k); std::cout << "最小的 " << k << " 个数是: "; for (int num : smallestK) { std::cout << num << " "; } std::cout << std::endl; return 0; } ``` --- ### ✅ 示例输入输出: ``` 请输入数组长度 n: 10 请输入数组元素(空格分隔): 7 10 4 3 20 15 1 5 6 8 请输入 K 值: 4 最小的 4 个数是: 1 3 4 5 ``` --- ### ✅ 时间复杂度分析: - 构建堆:`O(n)` - 取出 K 个最小元素:`O(k log n)` - 总体时间复杂度:`O(n + k log n)` --- ### ✅ 其他可选方法(拓展思路): | 方法 | 时间复杂度 | 说明 | |------|-------------|------| | 排序后取 K 个 | `O(n log n)` | 简单直接,但效率略低 | | 速选择算法 | 平均 `O(n)`,最坏 `O(n^2)` | 适合只找第 K 小元素 | | 最大堆(保留 K 个最小值) | `O(n log k)` | 更适合大数据流场景 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值