找到无序数组中最小的k个数

本文介绍了一种寻找数组中最小K个数的有效算法,通过维护一个大小为K的大根堆,使得时间复杂度降低到O(NLogK),并提供了详细的实现代码。

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

题目:给定一个无序整数数组arr,找到其中最小的k个数

要求:如果数组arr的长度为n,排序之后自然可以得到最小的k个数,此时时间复杂度与排序的时间复杂度相同均为O(NlogN),本题要求实现时间复杂度为O(NLogK).

1.O(NLogK)的方法,即一直维护一个有k个数的最大的大根堆,这个堆是目前选出的k个最小数,在堆里的k个元素中堆顶的元素是最大的一个。

接下来遍历整个数组,遍历的过程中看当前数是否比堆顶元素小。如果是,就把堆顶的元素替换成当前的数,然后从堆顶的位置调整堆,替换后堆的最大元素的位置依旧在堆顶;如果不是,则不进行任何操作,继续遍历下一个数;遍历完成后,堆中的k个数就是所有数组中最小的k个数。

具体请参看如下代码中的getMinKNumsByHeap方法,代码中的heapInsert和heapify方法分别为堆排序中的建堆和调整堆的实现。

 1 public int[]  getMinKNumsByHeap(int[] arr,int k)
 2 {
 3     if(k<1 || k>arr.length)
 4             return arr;
 5     int[] kHeap=new int[k];
 6     for(int i=0;i<k;i++)
 7     {
 8         heapInsert(kHeap,arr[i],i);
 9      }
10    for(int i=k;i<arr.length;i++)
11   {
12        if(arr[i]<kHeap[0])
13      {
14           kHeap[0]=arr[i];
15          heapify(kHeap,0,k);
16      }
17    }
18   return kHeap;
19 }
20 
21 public void heapInsert(int[] arr,int value,int index)
22 {
23    arr[index]=value;
24    while(index!=0)
25   {
26     int parent=(index-1)/2;
27     if(arr[parent]<arr[index])
28     {
29        swap(arr,parent,index);
30        index=parent;
31     }
32   else
33      break;
34   }
35 }
36 
37 public void  heapify(int[] arr,int index,int heapSize)
38 {
39     int left=index*2+1;
40     int right=index*2+2;
41     int largest=index;
42    while(left<heapSize)
43  {
44      if(arr[left]>arr[index])
45              largest=left;
46      if(right<heapSize&&arr[right]>arr[largest])
47               largest=right;
48      if(largest!=index)
49               swap(arr,largest,index);
50       else
51         break;
52     index=largest;
53     left=index*2+1;
54     right=index*2+2;
55     }
56 }
57 
58 public void swap(int[] arr,int index1,int index2)
59 {
60     int tmp=arr[index1];
61     arr[index1]=arr[index2];
62     arr[index2]=tmp;
63 }
View Code

 

转载于:https://www.cnblogs.com/guanling222/p/5771180.html

### 使用最大堆和最小堆寻找无序数组中位数 为了高效地找到无序数组中的中位数及其原始下标,可以采用最大堆和最小堆相结合的方法。这种方法能够在O(log n)时间内完成插入操作,并保持数据结构平衡以便随时获取当前的中位数值。 具体实现如下: 1. 创建个优先队列:一个是大根堆用于存储较小的一半元素;另一个是小根堆用来保存较大的一半元素。 2. 当新加入一个元素时,如果这个值小于等于大根堆顶,则将其放入大根堆;反之则进入小根堆。 3. 维护这个堆之间的大小关系使得它们要么相等,要么大根堆多出一个小于等于小根堆顶部的那个唯一额外项。 4. 如果总数量为奇数,则中位数就是大根堆顶端元素;如果是偶数的话,那么中位数将是者顶端元素平均值得到的结果[^1]。 然而上述方法并不能直接给出原数组里的索引位置。对于这个问题,可以在向堆里添加元素的同时维护一个哈希表来追踪每个值对应的初始索引。这样,在最终确定中位数后就可以通过查表得到其原本所在的位置了。 另外一种更简单但效率稍低的办法是先复制一份输入列表并对其进行排序处理,再依据定义从中选出位于中央处的目标数字,最后回到未排序版本的数据集中定位该目标的具体地址[^2]。 下面是基于Python语言的一个简易示例程序展示如何利用快速排序思想配合映射机制获得所需结果: ```python def find_median_index(arr): import copy # 复制数组以防修改原有数据 sorted_arr = copy.deepcopy(arr) # 对副本执行排序 sorted_arr.sort() length = len(sorted_arr) median_value = (sorted_arr[length // 2] + sorted_arr[(length - 1) // 2]) / 2 index_map = {value: idx for idx, value in enumerate(arr)} try: result_idx = index_map[median_value] except KeyError as e: # 若不存在确切匹配的情况(例如浮点型中位数) lower_bound = min(index_map.keys(), key=lambda k: abs(k-median_value)) result_idx = index_map[lower_bound] return result_idx test_array = [7, 9, 3, 5, 1] print(f"The original array is :{test_array}") result = find_median_index(test_array) print(f"Median element's original position was at index:{result}.") ``` 此代码片段展示了如何创建一个新的已排序序列以识别其中心值,并借助字典对象建立从值到原来索引间的对应关系,从而能够返回中位数最初所在的下标位置[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值