215. Kth Largest Element in an Array

这篇博客讨论了如何在不完全排序数组中找到第k大的元素,避免使用O(nlogn)的时间复杂度。作者介绍了采用快速排序思想,通过不断调整pivot找到正确位置的方法,虽然具体时间复杂度不易精确计算,但比快速排序更优。同时,注意数组长度大于3时的处理以及结果转换。附带AC代码,运行时间8ms,在C++中表现优秀。

https://leetcode.com/problems/kth-largest-element-in-an-array/

1. 思路

求第k大的数。如果先排序再取第k个数,时间复杂度O(nlogn),太naive

采用快速排序的思路,每次遍历后返回pivot(快速排序中的专有名词)的位置,如果该位置不是k,则对新的更小的数组执行快速排序操作,依次类推,直到pivot的位置是k为止。

时间复杂度分析:

第一遍快排肯定循环了n次,但第二次快排不需要循环n次了,后面循环的次数会越来越小。总体来说时间复杂度是比快速排序要小的,因为每次快排之后只需要对左边或者右边再排序,而不用像传统快速排序那样左边右边再排序一遍。

传统快速排序的时间复杂度为T(N)=T(N/2)*2+cN,求解通项公式为T(N)=cNlog(N)+N=O(NlogN)

那么此题的时间复杂度为T(N)=T(N/2)+cN,通项公式似乎不太好解,而且如果中间哪一步pivot的位置是k了,后面的步骤是不用再跑的,就更快了。总之关于时间复杂度这里还没有很好的解释,只能说是比快排要快的。但是LeetCode的discuss中说这个方法时间复杂度是O(n),如果有能解释的同学欢迎指导,谢谢。

2. 注意的细节

对三个数进行排序,这三行的顺序不能变

        if(nums[left]>nums[mid]) swap(nums[left], nums[mid]);
        if(nums[left]>nums[right]) swap(nums[left], nums[right]);
        if(nums[mid]>nums[right]) swap(nums[right], nums[mid]);

如果数组的长度大于3,就没有必要快排了(也做不了快排),直接返回pivot的位置

            if(right-left>=3) mid = quick_sort(nums, left, right);
            else mid=(left+right)/2;

求的是第k大的数,但是pivot的位置是从小到大排序的,所以需要转换一下

target=nums.size()-k;

3. AC代码(Runtime: 8 ms, faster than 98.79% of C++ )

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        int left=0, right=nums.size()-1, target=nums.size()-k;
        int mid;
        while(left < right){
            median(nums, left, right);
            if(right-left>=3) mid = quick_sort(nums, left, right);
            else mid=(left+right)/2;
            if(mid > target) right = mid-1;
            else if(mid < target) left = mid + 1;
            else return nums[mid]; 
        }
        return nums[left];
    }
    void median(vector<int>& nums, int left, int right){
        int mid = (left+right)/2;
        if(nums[left]>nums[mid]) swap(nums[left], nums[mid]);
        if(nums[left]>nums[right]) swap(nums[left], nums[right]);
        if(nums[mid]>nums[right]) swap(nums[right], nums[mid]);
        swap(nums[mid], nums[right-1]);
    }
    int quick_sort(vector<int>& nums, int left, int right){
        int i = left, j=right-1;
        while(i<j){
            while(nums[++i]<nums[right-1]){}
            while(nums[--j]>nums[right-1]){}
            if(i<j) swap(nums[i], nums[j]);
            else break;
        }
        swap(nums[i], nums[right-1]);
        return i;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值