堆排序 VS 快速排序 解决 TOP K 问题

2021-05-30 02:07

阅读:675

标签:根据   air   pivot   底层实现   for   class   交换   public   实现   

解决 TOP k 问题通常可采用 堆排序 和 快速排序的思想

1.  大根堆(前 K 小) / 小根堆(前 K 大):   时间复杂度O(NlogK) 

c++ STL 中提供了  priority_queue 实现堆的基本功能,比如 priority_queue pq;

堆 pq 的元素都是 int 型的,priority_queue 默认使用 vector 作为 堆的底层实现,pq默认是个

大根对,priority_queue pq 等同于 priority_queue ,less > pq;

小根堆 :priority_queue ,greater > pq1,

堆中的元素必须 是可以比较大小的。

Tips : c++  std :: pair,是可以比较大小的。比较的逻辑如下:

1 templateclass _Ty1, class _Ty2>
2  inline  bool operatorconst pair<_ty1 _ty2>& _Left, 
3                                   const pair<_ty1 _ty2>& _Right)
4     {    // test if _Left 
5     return (_Left.first 6         !(_Right.first  _Right.second);
7     }

2 、用快排变形高效解决 TopK 问题:时间复杂度O(N)

注意找前 K 大/前 K 小问题不需要对整个数组进行 O(NlogN)O(NlogN) 的排序!

比如找到数组 arr 中的前 k 小个元素,使用快速排序的划分操作 一次可以确定数组中一个元素的最终位置。不断缩小划分的范围,

最终的目标是确定位置  k - 1 上的最终元素。

根据快速排序思想,要是数组的 k -1 位置上的元素确定了,则 [0:k-1] 就是所求的 前 K 小个元素。

求 前 K 大个元素 需使用划分法 确定 n - k 位置上的元素,[n-k,k-1] 就是所求的 前 k 大个元素。

 

3. 示例

技术图片

 

 方法一.  快速排序解决 TOP K 问题

 1 class Solution {
 2 public:
 3     vectorint>> kClosest(vectorint>>& points, int k)
 4     {
 5         const int n = points.size();
 6         vectorint> index_vec(n);
 7         for(int i = 0 ; i i)
 8         {
 9             index_vec[i] = i;
10         }
11         int left = 0, right = n - 1;
12         bool flag = false;
13         while(left  right)
14         {
15             int t = partition(points,index_vec,left,right);
16             if(t == -1) break;
17             if(t == k - 1)
18             {
19                 flag = true;
20                 break;
21             }
22             else if( t > k - 1)
23             {
24                 right = t - 1;
25             }
26             else
27             {
28                 left = t + 1;
29             }
30         }
31         vectorint>> res;
32         if(flag)
33         {
34             for(int i = 0;i i)
35             {
36                 res.push_back(points[index_vec[i]]);
37             }
38         }
39         return res;
40     }
41     
42     int partition(vectorint>>& points,vectorint> &index_vec,int l,int r)
43     {
44         if(l > r)
45         {
46             return -1;
47         }
48         int i = l,j = r;
49         int pivot = cal_dist(points[index_vec[l]]);
50         while( true )
51         {
52             while(i i;
53             while(i = pivot) --j;
54             if(i > j)
55             {
56                 break;
57             }
58             std::swap(index_vec[i],index_vec[j]);
59         }
60         std::swap(index_vec[l],index_vec[j]);//最后一次交换 index_vec[l] 最终的位置确定
61         return j;
62     }
63     
64     inline int cal_dist(vectorint>& point)
65     {
66         return point[0] * point[0] + point[1] * point[1];
67     }
68 };

方法二.  大根堆解决 TOP K 问题

 1 //Top K we
 2   class my_less {
 3     public:
 4         bool operator()(const pairint, int>& pr1, const pairint, int>& pr2) {
 5             return pr1.first  pr2.first;
 6         }
 7     };
 8 
 9 class Solution {
10 public:
11     vectorint>> kClosest(vectorint>>& points, int K)
12     {
13         //priority_queue,vector>,my_less> q;//大顶堆
14         priority_queueint, int>> q;
15         const int n = points.size();
16         for (int i = 0; i i)
17         {
18             int dist = points[i][0] * points[i][0] + points[i][1] * points[i][1];
19             if(q.size()  K)
20             {
21                q.push(make_pair(dist,i));
22                 continue;
23             }
24             if (dist  q.top().first)
25             {
26                 q.pop();
27                 q.emplace(dist, i);
28             }
29         }
30         vectorint>> ans;
31         while (!q.empty())
32         {
33             ans.push_back(points[q.top().second]);
34             q.pop();
35         }
36         return ans;
37     }
38 };

 

 

 

 

堆排序 VS 快速排序 解决 TOP K 问题

标签:根据   air   pivot   底层实现   for   class   交换   public   实现   

原文地址:https://www.cnblogs.com/wangxf2019/p/14756010.html


评论


亲,登录后才可以留言!