TOP-K :快速选择算法 & 堆解法

1. 从快排partition过程借鉴而来,利用partion过程每次能确定一个元素位置来实现。

此算法期望时间复杂度为O(N),最差为O(N^2)。

每次确定了一个元素位置后,就能判断待查的topk个元素是在哪个分区,只需要递归一个分区即可。

代码如下:

int quickSelect(vector<int>&, int, int, int);

int findKthSmallest(vector<int>& arrs, int k) {
    int sz = arrs.size();
    if (k > sz)
        return -1;
    return quickSelect(arrs, k, 0, sz - 1);
}

int quickSelect(vector<int>& arrs, int k, int l, int r) {
    //选pivot为最右边那个  更好的方式是随机选一个
    //int pivot = arrs[r];
    int random_idx = rand() % (r-l+1) + l;
    swap(arrs[random_idx], arrs[r]);
    //int pivot = arrs[r];

    // partition过程
    int pivot = arrs[r];
    int i = l - 1;
    for (int j = l; j < r; ++j) {  //维护一个<= > ?三个区域
        if (arrs[j] <= pivot) {
            swap(arrs[++i], arrs[j]);
        }
    }
    swap(arrs[i+1], arrs[r]);  //i+1为最后中轴所在的位置

    //递归过程
    if (k == (i+1)) {
        return arrs[i+1];
    }
    else if (k < (i+1)) {
        return quickSelect(arrs, k, l, i);
    }
    else {
        return quickSelect(arrs, k, i+2, r);
    }
}

2. 利用堆来实现TOP-K问题

维护一个包含K个元素的堆,求第K大的维护小根堆,求第K小的维护大根堆。

时间复杂度为:O(nlogk)。

代码如下:

//建堆 + 拔尖 + 调整
void adjustHeap(vector<int>& arr, int i, int len);

int findKthSmallest(vector<int>& nums, int k) {
    //建立一个大顶堆
    vector<int> arr(k, 0);
    for (int i = 0; i < k; ++i) {
        arr[i] = nums[i];
    }
    for (int i = arr.size() / 2; i >= 0; --i) {
        adjustHeap(arr, i, arr.size());
    }

    for (int i = k; i < nums.size(); ++i) {
        if (nums[i] >= arr[0])
            continue;
        arr[0] = nums[i];
        adjustHeap(arr, 0, arr.size());
    }
    return arr[0];
}

//调整
void adjustHeap(vector<int>& arr, int i, int len) { int tmp = arr[i]; for (int k = 2*i+1; k < len; k = k*2+1) { if (k < len-1 && arr[k] <= arr[k+1]) k++; if (arr[k] > tmp) { arr[i] = arr[k]; i = k; } else break; } arr[i] = tmp; }

以上是常用的两种解法,另外:

复杂度更高的解法有:

  1. 冒泡,时间复杂度O(KN)或者O((N-K)N),考虑K与n/2的大小;
  2. 直接用别的排序手段全排序,如归并,O(NlogN)。

复杂度更低的解法:

  1. BFPRT算法,分5组,每组取中位数,可以每次筛选掉更多的元素,时间复杂度严格的O(N)。

其他的变种,大文件中具有超大规模数,求TOP-K:

  • 可以采用分治算法,结合哈希算法来分到不同文件,每个小文件进行TOP-K处理,再进行合并,类似Map-Reduce过程。

 

posted @ 2022-08-10 10:09  Ray-ss  阅读(263)  评论(0编辑  收藏  举报