zoukankan      html  css  js  c++  java
  • 堆排序 VS 快速排序 解决 TOP K 问题

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

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

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

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

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

    小根堆 :priority_queue <int,vector<int>,greater<int> > pq1,

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

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

    1 template<class _Ty1, class _Ty2>
    2  inline  bool operator<(const pair<_Ty1, _Ty2>& _Left, 
    3                                   const pair<_Ty1, _Ty2>& _Right)
    4     {    // test if _Left < _Right for pairs
    5     return (_Left.first < _Right.first ||
    6         !(_Right.first < _Left.first) && _Left.second < _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     vector<vector<int>> kClosest(vector<vector<int>>& points, int k)
     4     {
     5         const int n = points.size();
     6         vector<int> index_vec(n);
     7         for(int i = 0 ; i < n ; ++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         vector<vector<int>> res;
    32         if(flag)
    33         {
    34             for(int i = 0;i < k; ++i)
    35             {
    36                 res.push_back(points[index_vec[i]]);
    37             }
    38         }
    39         return res;
    40     }
    41     
    42     int partition(vector<vector<int>>& points,vector<int> &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 <= j && cal_dist(points[index_vec[i]]) <= pivot) ++i;
    53             while(i <= j && cal_dist(points[index_vec[j]]) >= 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(vector<int>& 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 pair<int, int>& pr1, const pair<int, int>& pr2) {
     5             return pr1.first < pr2.first;
     6         }
     7     };
     8 
     9 class Solution {
    10 public:
    11     vector<vector<int>> kClosest(vector<vector<int>>& points, int K)
    12     {
    13         //priority_queue<pair<int, int>,vector<pair<int, int>>,my_less> q;//大顶堆
    14         priority_queue<pair<int, int>> q;
    15         const int n = points.size();
    16         for (int i = 0; i < n; ++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         vector<vector<int>> ans;
    31         while (!q.empty())
    32         {
    33             ans.push_back(points[q.top().second]);
    34             q.pop();
    35         }
    36         return ans;
    37     }
    38 };

     

  • 相关阅读:
    python 线程Queue 用法代码展示
    Python中的join()函数的用法
    python 中爬虫 content和text的区别
    免费代理ip爬虫分享
    django数据库的表已迁移的不能重新迁移的解决办法
    RuntimeError: Model class app_anme.models.User doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.---python学习错误记录
    MYSQL查询操作 详细
    mysql数据库的基本操作命令总结
    http短连接与长连接简介
    浅谈http协议
  • 原文地址:https://www.cnblogs.com/wangxf2019/p/14756010.html
Copyright © 2011-2022 走看看