[leetCode] 分治法之 Kth Largest Element Selection Algorithm实现 (6ms,超过99%)

来源:互联网 发布:js获取HTML对象 编辑:程序博客网 时间:2024/06/04 12:54

题目描述

题目描述

题目分析:

这题是出现过很多次的经典题目,但是这次是正好在算法课上学习了selection算法后,找来实践的。上次这道题目选择的是使用优先队列,用造好的轮子毕竟是简单,这次的selection算法是选择的Wikipedia的Quickselect词条下的伪代码实现。其中有两种,一种是尾递归实现,另一种是用循环模拟递归实现,不需要调用函数的循环实现当然更快,因此选用了循环的方式实现。以下给出Wikipedia此词条的超链接,已经参考的伪代码https://en.wikipedia.org/wiki/Quickselect

伪代码1
伪代码2

时间复杂度分析:

Quickselect的算法的时间复杂度在好的情况下,可以达到O(nlogn),但是这依赖于能否选择到好的pivot,当最坏情况发生,时间复杂度会退化到O(n2)。我尝试了两次,一次是使用固定的pivot: pivotIndex = (l + r) >>1,另一次选择使用了随机数 pivotIndex = int(rand() % (r-l +1)) + l
实际上,使用随机数的情况大部分消耗时间都是和固定的一样,但是有时候能快30%,下图是其中最快的一次。

运行时间

实际上,我曾经跑过discuss中其他排名较高的人的代码,都需要50ms左右,没有能进10ms的,而这个算法可以稳定在9ms以内,可以说是非常快了。所以实际时间复杂度可以说是非常低的

代码

class Solution {public:    int findKthLargest(vector<int>& nums, int k) {        // change k from kth largest to kth smallest        srand((unsigned)time(NULL));        k = nums.size() - k;        int l = 0, r = nums.size()-1;        while (true) {            if (l == r) return nums[l];            int pivotIndex = int(rand() % (r-l +1)) + l;            pivotIndex = partition(nums, l, r, pivotIndex);            if (k == pivotIndex) return nums[k];            else if (k < pivotIndex) r = pivotIndex -1;            else l = pivotIndex +1;        }    }    int partition(vector<int>& nums, int l, int r, int pivotIndex) {        int pivotValue = nums[pivotIndex], storeIndex = l;        swap(nums[pivotIndex], nums[r]);        for (int i = l; i < r; i++) {            if (nums[i] < pivotValue) {                swap(nums[storeIndex], nums[i]);                storeIndex++;            }        }        swap(nums[r], nums[storeIndex]);        return storeIndex;    }};
阅读全文
0 0